当前位置:  开发笔记 > 编程语言 > 正文

这个C++结构初始化技巧是否安全?

如何解决《这个C++结构初始化技巧是否安全?》经验,为你挑选了4个好方法。

我不是必须记住初始化一个简单的'C'结构,而是可以从它派生并在构造函数中将它归零,如下所示:

struct MY_STRUCT
{
    int n1;
    int n2;
};

class CMyStruct : public MY_STRUCT
{
public:
    CMyStruct()
    {
        memset(this, 0, sizeof(MY_STRUCT));
    }
};

这个技巧通常用于初始化Win32结构,有时可以设置无处不在的cbSize成员.

现在,只要memset调用没有虚函数表来销毁,这是一种安全的做法吗?



1> Johannes Sch..:

您可以简单地初始化基数,并将其所有成员清零.这是有保证的

struct MY_STRUCT
{
    int n1;
    int n2;
};

class CMyStruct : public MY_STRUCT
{
public:
    CMyStruct():MY_STRUCT() { }
};

为了使其工作,基类中应该没有用户声明的构造函数,就像在您的示例中一样.

memset对此并不讨厌.它不能保证memset在您的代码中有效,即使它应该在实践中起作用.


这是最相关和正确的答案.(我想知道是否有一些东西可以在SO上完成,以便将平衡从"最早的"答案转移到"最正确的"答案.不幸的是,目前早期的答案在大多数时候都击败了正确答案.)

2> paercebal..:

前言:

虽然我的答案仍然没问题,但我发现litb的答案远非我的,因为:

    它告诉我一个我不知道的技巧(litb的答案通常有这种效果,但这是我第一次写下来)

    它完全回答了问题(即将原始struct的部分初始化为零)

所以,请在我之前考虑一下litb的答案.事实上,我建议问题的作者将litb的答案视为正确答案.

原始答案

将一个真实对象(即std :: string)等放入其中将会破坏,因为真实对象将在memset之前初始化,然后由零覆盖.

使用初始化列表对g ++不起作用(我很惊讶......).而是在CMyStruct构造函数体中初始化它.它将是C++友好的:

class CMyStruct : public MY_STRUCT
{
public:
    CMyStruct() { n1 = 0 ; n2 = 0 ; }
};

PS:我当然认为你确实无法控制MY_STRUCT.使用控件,您可以直接在MY_STRUCT中添加构造函数,并忘记继承.请注意,您可以将非虚方法添加到类似C的结构中,并且仍然将其表现为结构.

编辑:在Lou Franco的评论之后添加了缺失的括号.谢谢!

编辑2:我在g ++上尝试了代码,由于某种原因,使用初始化列表不起作用.我使用body构造函数更正了代码.不过,解决方案仍然有效.

请重新评估我的帖子,因为原始代码已更改(有关详细信息,请参阅changelog).

编辑3:在阅读Rob的评论之后,我猜他有一个值得讨论的观点:"同意,但这可能是一个巨大的Win32结构,可能会随着新的SDK而改变,因此memset是未来的证明."

我不同意:了解微软,它不会因为需要完美的向后兼容性而改变.他们将创建一个扩展的MY_STRUCT Ex结构,其初始布局与MY_STRUCT相同,末尾有附加成员,并且可通过"size"成员变量识别,如用于RegisterWindow,IIRC的结构.

所以Rob的评论中剩下的唯一有效点是"巨大的"结构.在这种情况下,也许memset更方便,但是你必须使MY_STRUCT成为CMyStruct的变量成员而不是继承它.

我看到另一个黑客,但我想这会因为可能的结构对齐问题而中断.

编辑4:请看看Frank Krueger的解决方案.我不能保证它是可移植的(我猜它是),但从技术角度来看它仍然很有趣,因为它显示了一种情况,在C++中,"this"指针"地址"从其基类移动到其继承类.


您可以执行`CMyStruct():MY_STRUCT(){}`并且所有这些整数都将为零.
@paercebal:嗯,这意味着一个破坏的编译器,这几乎不是反对`()`形式的论据.并且*默认初始化*和*根本没有初始化*之间存在巨大差异,即使对于基本类型也是如此.对于像OP中那样的结构,`()`初始值设定项会将所有内容都设置为零.

3> Drealmer..:

比memset好多了,你可以用这个小技巧代替:

MY_STRUCT foo = { 0 };

这会将所有成员初始化为0(或其默认值iirc),无需为每个成员指定值.


首先,这就是你在C++中用C语言做的这个特殊的小技巧转换为`MY_STRUCT foo = {};`(因为并非所有数据类型都可以用C++中的文字0初始化).其次,当我们讨论构造函数初始化列表时,直接分析只是在初始化列表中包含`MY_STRUCT()`.
这个技巧的问题是它在GCC中污染了`-Wmissing-field-initializers`,这是一个非常有用的警告.

4> Frank Kruege..:

这会让我感觉更安全,因为它应该工作,即使有一个vtable(或编译器会尖叫).

memset(static_cast(this), 0, sizeof(MY_STRUCT));

我相信你的解决方案会起作用,但我怀疑在混音memset和课程时有任何保证.

推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有