【问题标题】:Are members of a C++ struct initialized to 0 by default?C++ 结构的成员是否默认初始化为 0?
【发布时间】:2010-11-07 08:44:35
【问题描述】:

我有这个struct

struct Snapshot
{
    double x; 
    int y;
};

我希望 xy 为 0。默认情况下它们是 0 还是我必须这样做:

Snapshot s = {0,0};

还有哪些其他方法可以将结构归零?

【问题讨论】:

标签: c++


【解决方案1】:

如果你不初始化结构,它们不为空。

Snapshot s; // receives no initialization
Snapshot s = {}; // value initializes all members

第二个将使所有成员为零,第一个使它们保持未指定的值。注意它是递归的:

struct Parent { Snapshot s; };
Parent p; // receives no initialization
Parent p = {}; // value initializes all members

第二个将使p.s.{x,y} 为零。如果结构中有构造函数,则不能使用这些聚合初始值设定项列表。如果是这种情况,您将必须为这些构造函数添加适当的初始化

struct Snapshot {
    int x;
    double y;
    Snapshot():x(0),y(0) { }
    // other ctors / functions...
};

将 x 和 y 都初始化为 0。请注意,您可以使用 x(), y() 来初始化它们而不管它们的类型:然后是值初始化,通常会产生一个适当的初始值(0 代表 int,0.0 代表 double,调用具有用户声明的构造函数的用户定义类型的默认构造函数,...)。这很重要,特别是如果您的结构是模板。

【讨论】:

  • 这会在我的编译器中产生很多警告。
  • Roger:尝试在初始化程序中使用命名结构,这就是我所做的,我在 VC 2012 中没有收到任何警告:Snapshot s = Snapshot();
  • @Johannes Schaub - litb Snapshot s = {}; 是否会为非 POD 成员工作(用于归零)?
  • C++11 现在允许您在结构或类的定义中初始化它们,如下所示: struct Snapshot { double x{0}; //带大括号 int y = 0 ; //或者只是老派风格的“按分配”,这也是真正的初始化 };
  • 是“快照 s = {};”标准的一部分?
【解决方案2】:

不,默认情况下它们不是 0。确保所有值或默认为 0 的最简单方法是定义构造函数

Snapshot() : x(0), y(0) {
}

这可确保所有使用的 Snapshot 都具有初始化值。

【讨论】:

  • 缺点是struct不再是POD类型,因为它有一个构造函数。这会破坏一些操作,例如将其写入临时文件。
  • @finnw:C++11 修复了这个问题,虽然结构不是 POD,但它是“标准布局”。
【解决方案3】:

一般来说,不会。但是,在函数中声明为文件范围或静态的结构 / 将 / 初始化为 0(就像这些范围的所有其他变量一样):

int x; // 0
int y = 42; // 42
struct { int a, b; } foo; // 0, 0

void foo() {
  struct { int a, b; } bar; // undefined
  static struct { int c, d; } quux; // 0, 0
}

【讨论】:

  • 这真的不是一个安全的假设。你不应该依赖你没有初始化的任何东西的价值
  • 静态存储持续时间对象始终初始化为零 - 请参阅 stackoverflow.com/questions/60653/… 以获取标准的引用。这是否是好的风格是另一回事。
【解决方案4】:

用 POD 你也可以写

Snapshot s = {};

你不应该在 C++ 中使用 memset,memset 的缺点是如果结构中存在非 POD,它会破坏它。

或者像这样:

struct init
{
  template <typename T>
  operator T * ()
  {
    return new T();
  }
};

Snapshot* s = init();

【讨论】:

  • @LightnessRacesinOrbit 哦,哇?
  • @Andy Most Vexing Parse 将看起来像普通 ctor 的东西——SomeType foo(); 是典型的,尽管它也可能发生在其他人身上——变成函数定义(在这种情况下,函数 @987654324 @ 返回SomeType)。对不起,死灵,但如果其他人偶然发现这个,我想我会回答。
【解决方案5】:

在 C++ 中,使用无参数构造函数。在 C 中你不能有构造函数,所以使用 memset 或 - 有趣的解决方案 - 指定初始化器:

struct Snapshot s = { .x = 0.0, .y = 0.0 };

【讨论】:

  • 我相信这是 C,而不是 C++。在某些 C++ 编译器下将无法编译。我在 Cygwin 或 MinGW 下遇到了编译失败。
  • 这适用于 C 或 C++20。在旧的 C++ 标准中,只有当你的编译器是优雅的时它才会起作用。
【解决方案6】:

由于这是一个 POD(本质上是一个 C 结构),因此以 C 方式对其进行初始化没有什么坏处:

Snapshot s;
memset(&s, 0, sizeof (s));

或类似

Snapshot *sp = new Snapshot;
memset(sp, 0, sizeof (*sp));

不过,我不会在 C++ 程序中使用 calloc()

【讨论】:

  • 双倍同样适用; all-bits-zero 不一定是 0.0 。但是,您可以检查您是否有 IEEE754 双打,在这种情况下它必须工作。
【解决方案7】:

我相信正确的答案是它们的值是未定义的。通常,它们在运行代码的调试版本时被初始化为 0。运行发布版本时通常不是这种情况。

【讨论】:

  • 实际上调试版本恰好在内存中的那些地方已经有0。这和初始化不一样!
【解决方案8】:

将 pod 成员移动到基类以缩短您的初始化列表:

struct foo_pod
{
    int x;
    int y;
    int z;
};

struct foo : foo_pod
{
    std::string name;
    foo(std::string name)
        : foo_pod()
        , name(name)
    {
    }
};

int main()
{
    foo f("bar");
    printf("%d %d %d %s\n", f.x, f.y, f.z, f.name.c_str());
}

【讨论】:

    【解决方案9】:

    我知道这个问题太老了,但是这个问题在谷歌上弹出给我,我发现了另一种方式,我想我会在这里添加它:

    Snapshot s {};
    

    我不确定此语法需要什么 C/C++ 语言版本。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    相关资源
    最近更新 更多