【问题标题】:Proper way to initialize C++ structs初始化 C++ 结构的正确方法
【发布时间】:2011-08-20 08:12:40
【问题描述】:

我们的代码涉及一个 POD(普通旧数据结构)结构(它是一个基本的 c++ 结构,其中包含其他结构和 POD 变量,需要在开始时进行初始化。)

根据我的read,看来:

myStruct = (MyStruct*)calloc(1, sizeof(MyStruct));

应该将所有值初始化为零,如下所示:

myStruct = new MyStruct();

但是,当以第二种方式初始化结构时,Valgrind 稍后会在使用这些变量时抱怨“条件跳转或移动取决于未初始化的值”。是我的理解有缺陷,还是 Valgrind 抛出了误报?

【问题讨论】:

  • 另外,请注意 new MyStruct() 不需要在 C++03 中设置任何填充字节。在 C++0x 中是这样。在 C++0x 中,任何填充位都将设置为 0。
  • 感谢您的关注,我编辑了我的问题。
  • 相关常见问题解答:stackoverflow.com/questions/620137/…
  • 据我了解,您不应该收到该错误消息。也许您的数据结构不是 POD?你能把你的代码缩减为仍然展示这种行为的最小程序,然后发布那个提炼的程序吗? (见sscce.org)。
  • 什么编译器?你能发布 MyStruct 的定义吗?

标签: c++ struct initialization valgrind calloc


【解决方案1】:

在 C++ 中,类/结构是相同的(就初始化而言)。

一个非 POD 结构也可以有一个构造函数,这样它就可以初始化成员。
如果您的结构是 POD,那么您可以使用初始化程序。

struct C
{
    int x; 
    int y;
};

C  c = {0}; // Zero initialize POD

您也可以使用默认构造函数。

C  c = C();      // Zero initialize using default constructor
C  c{};          // Latest versions accept this syntax.
C* c = new C();  // Zero initialize a dynamically allocated object.

// Note the difference between the above and the initialize version of the constructor.
// Note: All above comments apply to POD structures.
C  c;            // members are random
C* c = new C;    // members are random (more officially undefined).

我相信 valgrind 会抱怨,因为这就是 C++ 过去的工作方式。 (我不确定何时使用零初始化默认构造升级 C++)。最好的办法是添加一个初始化对象的构造函数(结构体是允许的构造函数)。

附注:
很多初学者都尝试重视 init:

C c(); // Unfortunately this is not a variable declaration.
C c{}; // This syntax was added to overcome this confusion.

// The correct way to do this is:
C c = C();

快速搜索“Most Vexing Parse”将提供比我更好的解释。

【讨论】:

  • 您对 C++ 中变量的这种零初始化有参考吗?最后我听说,它仍然具有与 C 相同的行为。 IIRC,MSVC 编译器甚至在某些时候丢弃了零初始化未初始化的成员(出于性能原因,我假设),这显然给其他 MS 部门带来了相当严重的问题 :)
  • 不,C(),但似乎是you are right
  • 对于 POD 类,TT() 始终将标量子对象初始化为零。 C++98 中顶层初始化的名称与 C++03 中的不同(“默认初始化”与“值初始化”),但 POD 的最终效果是相同的。 C++98 和 C++03 中的所有值都为零。
  • @RockyRaccoon C c(); 不幸的是,它不是一个变量声明,而是一个函数的前向声明(一个名为“c”的函数,它不带参数并返回一个 C 类型的对象)。谷歌:最令人头疼的解析
  • @RockyRaccoon 这里的区别以及您在评论中链接到的问题;是在这种情况下,构造函数中没有使用任何参数。所以编译器很难解析这个并告诉变量声明和函数的前向声明之间的区别。它选择前向函数声明。如果您在构造函数中需要一个参数,那么编译器可以看到这是一个变量声明,没有任何问题。 C c(4); 是一个有效的变量声明。
【解决方案2】:

从您告诉我们的情况来看,这在 valgrind 中似乎是误报。 new 语法与 () 应该值初始化对象,假设它是 POD。

是否有可能您的结构的某些子部分实际上不是 POD 并且这会阻止预期的初始化?您是否能够将您的代码简化为仍然标记 valgrind 错误的可发布示例?

另外,也许您的编译器实际上并未对 POD 结构进行值初始化。

在任何情况下,最简单的解决方案可能是根据结构/子部分的需要编写构造函数。

【讨论】:

    【解决方案3】:

    我写了一些测试代码:

    #include <string>
    #include <iostream>
    #include <stdio.h>
    
    using namespace std;
    
    struct sc {
        int x;
        string y;
        int* z;
    };
    
    int main(int argc, char** argv)
    {
       int* r = new int[128];
       for(int i = 0; i < 128; i++ ) {
            r[i] = i+32;
       }
       cout << r[100] << endl;
       delete r;
    
       sc* a = new sc;
       sc* aa = new sc[2];
       sc* b = new sc();
       sc* ba = new sc[2]();
    
       cout << "az:" << a->z << endl;
       cout << "bz:" << b->z << endl;
       cout << "a:" << a->x << " y" << a->y << "end" << endl;
       cout << "b:" << b->x << " y" << b->y <<  "end" <<endl;
       cout << "aa:" << aa->x << " y" << aa->y <<  "end" <<endl;
       cout << "ba:" << ba->x << " y" << ba->y <<  "end" <<endl;
    }
    

    g++编译运行:

    ./a.out 
    132
    az:0x2b0000002a
    bz:0
    a:854191480 yend
    b:0 yend
    aa:854190968 yend
    ba:0 yend
    

    【讨论】:

    • 好吧,我对 new sc;new sc(); 不太熟悉。我会认为缺少的括号是一个错误。但这似乎表明答案是正确的(当您使用默认构造函数时它会初始化为 0。)
    【解决方案4】:

    您需要初始化结构中的所有成员,例如:

    struct MyStruct {
      private:
        int someInt_;
        float someFloat_;
    
      public:
        MyStruct(): someInt_(0), someFloat_(1.0) {} // Initializer list will set appropriate values
    
    };
    

    【讨论】:

    • 在这种情况下,我使用的不是一个类,而是一个结构体。
    • 结构是一个类。编辑了我的帖子:)
    • 您不需要为 POD 执行此操作
    • 结构体如何拥有私有成员?
    • 什么意思?通过在它们前面添加私有,就像一个普通的类。
    【解决方案5】:

    由于它是一个 POD 结构,您始终可以将其 memset 为 0 - 这可能是初始化字段的最简单方法(假设这是适当的)。

    【讨论】:

    • 是结构体还是类与memset或创建构造函数的能力无关。参见例如stackoverflow.com/questions/2750270/c-c-struct-vs-class
    • 创建类后通常不会对其进行 memset,因为它的构造函数(可能)进行了初始化。
    • C++ 中的“类”和“结构”没有区别,除了默认保护(分别为私有和公共)。结构可以是非 POD,类可以是 POD,这些概念是正交的。
    • @mmutz 和 @Erik - 同意 - 缩短了我的答案以防止混淆。
    • memset() 不是最佳选择,您可以通过调用其默认 ctor 来对 POD 结构进行零初始化。
    【解决方案6】:

    在我看来这是最简单的方法。可以使用花括号“{}”初始化结构成员。例如,以下是有效的初始化。

    struct Point 
    { 
       int x, y; 
    };  
    
    int main() 
    { 
       // A valid initialization. member x gets value 0 and y 
       // gets value 1.  The order of declaration is followed. 
       struct Point p1 = {0, 1};  
    }
    

    有关于 c++ 中结构的好信息 - https://www.geeksforgeeks.org/structures-in-cpp/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多