有没有办法让 C++ 结构值初始化所有 POD 成员变量?

Posted

技术标签:

【中文标题】有没有办法让 C++ 结构值初始化所有 POD 成员变量?【英文标题】:Is there a way to make a C++ struct value-initialize all POD member variables? 【发布时间】:2010-10-14 07:05:56 【问题描述】:

假设我有一个同时具有 POD 和非 POD 成员变量的 C++ 结构:

struct Struct 
    std::string String;
    int Int;
;

为了让我的程序产生可重现的行为,我希望在构造时初始化所有成员变量。我可以为此使用初始化列表:

 Struct::Struct() : Int() 

问题是,一旦我需要更改结构并添加新的 POD 成员变量(比如 bool Bool),我就有可能忘记将其添加到初始化列表中。那么新的成员变量在struct构造过程中就不会被值初始化了。

我也不能使用memset() 技巧:

Struct::Struct()

   memset( this, 0, sizeof( *this ) ); //can break non-POD member variables

因为调用 memset() 覆盖已经构造的非 POD 成员变量可能会破坏这些。

在这种情况下,有没有办法强制所有 POD 成员变量的值初始化而不显式添加它们的初始化?

【问题讨论】:

我建议每个成员成为const。特别是当它们都是public 时,强制不变性真的很有意义。您可以使用数组初始化语法来创建实例:Struct s = "...", 0 ; @Daniel:我什么时候想把它放在容器里? @GMan:在这种情况下,我会将其放在std::shared_ptr 中。或者也许决定正确封装成员并删除const @Daniel:所有公众成员都没有错。 @Daniel:我不需要你和我一起玩扶手椅精神病医生,或者说我思想封闭。非常粗鲁。在这种情况下,根据我们掌握的信息,将成员全部设为const 并不是一个合适的解决方案,因为您已经更改了该类可以做什么。还有其他解决方案可以解决不改变可用性的问题。虽然这并不能消除您的解决方案可能适用于不同情况的可能性(我从未说过),但这确实意味着您的解决方案相对于其他解决方案而言存在不足。 【参考方案1】:

最简洁的方法是编写自动初始化模板类initialized<T>

编辑:我现在意识到,通过允许您声明 initialized<Struct>,它可以变得更加灵活。这意味着您可以在不修改原始Struct 的情况下声明初始化。默认初始化 'T()' 的灵感来自 Prasoons 的回答。

template<class T>  
struct initialized 
 
public: 

     initialized() 
         value = T(); 

    initialized(T t) 
         value = t; 

    initialized(const initialized<T>& x) 
         value = x.value; 

    T* operator &()  return &value;  

     operator T&()  return value;      

private: 
     T value; 
;


struct PodStruct 
            
    std::string String;      
    int Int; 
;  


struct GlorifiedPodStruct 
            
    std::string String;      
    initialized<int> Int; 
;  

void Test()

    GlorifiedPodStruct s;
    s.Int = 1;
    int b = s.Int;
    int * pointer = &s.Int;

    initialized<PodStruct> s2;

这可以编译,但可能需要更多的转换运算符,处理诸如 volatile 之类的关键字等。但你明白了。

【讨论】:

嗯。看起来不错,但是将 value 设为私有然后提供对它的完全访问权限的目的是什么?将其公开并删除转化不是更干净吗? @sharptooth:这个想法是你可以像使用int 一样使用initialized&lt;int&gt;。例如,initialized&lt;int&gt; a; int b=a; 有效。如果没有转换运算符,您将需要显式访问 value 成员。 @Martin B:是的,您说的直接访问是对的,我没有想到这一点。仍然将 value 设为私有是没有意义的。 @sharptooth:值是私有的还是不重要的。只是当initialized&lt;T&gt;T 完全可互换时,您无论如何都不需要访问value @Martin B:感谢您的澄清。【参考方案2】:

链接问题here

在这种情况下,有没有办法强制所有 POD 成员变量的值初始化而不显式添加它们的初始化?

我不确定这样的事情是否[直接]可行,但以下工作

prasoon@prasoon-desktop ~ $ cat check.cpp && clang++ check.cpp && ./a.out
#include <iostream>
struct Struct 
    std::string String;
    int Int;
    bool k;
    // add add add
;

struct InStruct:Struct

   InStruct():Struct()
;

int main()

   InStruct i;
   std::cout<< i.k << "  " << i.Int << std::endl; 

0  0
prasoon@prasoon-desktop ~ $ 

【讨论】:

-1 你很幸运并且得到了零,因为i 所在的内存恰好是零初始化的。标准保证这一点。 @Martin B :我认为它是由 C++03 保证的。请看我的问题here 我在那里学到了一些东西——我很抱歉。我正在删除反对票并添加赞成票。【参考方案3】:

你可以添加一个基础结构:

struct PODStruct

  PODStruct(unsinged int count)  memset( this, 0, count);
;

然后你的结构派生自这个基础结构,如果你有多个基础结构,则排在第一位,

struct Struct : PODStruct

  Struct();
  std::string Str;
  int Int;


Struc::Struct() : PODStruct(sizeof(Struct))


【讨论】:

这会导致 UB。您不能通过非 POD 类型 memset,例如 std::string

以上是关于有没有办法让 C++ 结构值初始化所有 POD 成员变量?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 是不是对 POD typedef 进行值初始化?

c++中用memset初始化数组可以初始化任何值吗?

值初始化 C++

让编译器检查数组初始值设定项的数量

有没有办法在类 c++ 中取消初始化变量

方便的 C++ 结构初始化