如何确保您的对象是零初始化?

时间:2015-04-02 12:40:46

标签: c++11 initialization zero default-constructor value-initialization

更新:我正在考虑是否有办法立即对整个班级进行零初始化,因为从技术上讲,人们可能会忘记添加“= 0”或“{ {1}}'在每个成员之后。其中一条评论提到,在{}形式的值初始化过程中,明确默认的无参数c-tor将启用零初始化。看http://en.cppreference.com/w/cpp/language/value_initialization我无法弄清楚哪些陈述指明了这一点。

由于C ++ 11改变了各种初始化结构的含义和语法,因此初始化是一个复杂的主题。我无法从其他问题中收集到足够好的信息。但请参阅,例如Writing a Default Constructor Forces Zero-Initialization?

我面临的具体问题是:我想确保我的类的成员都被归零为(1)声明默认c-tor的类,以及(2)那些不声明c-tor的类。 / p>

对于(2),使用MyClass c{};进行初始化会完成作业,因为它是值初始化的语法,转换为零初始化,或者如果您的类是聚合,则聚合初始化 - 其中成员为没有提供初始化程序(全部!)是零初始化。

但是对于(1)我仍然不确定什么是最好的方法。从我收集的所有信息中我了解到如果你提供默认的c-tor(例如,为了将某些成员设置为某些值),你必须明确地将其余成员归零,否则语法{}或C ++ 11 MyClass c = MyClass();将无法胜任。换句话说,在这种情况下,值初始化意味着只是调用你的c-tor,就是这样(没有归零)。

如果你声明一个带有值的c-tor,并将这些值设置为成员的子集,但你希望其他成员被归零,你会遇到同样的情况:没有做的简写它 - 我正在考虑3个选项:

MyClass c{};

我的推理是否正确? 选择哪3个选项?

3 个答案:

答案 0 :(得分:4)

使用类内初始化怎么样?

class Foo
{
    int _a{}; // zero-it
    int _b{}; // zero-it
public:
    Foo(int a): _a(a){} // over-rules the default in-class initialization
};

答案 1 :(得分:3)

选项4和5:

选项4:


MyClass(int a) :a(a), b(0), c(0)
  {
  }

选项5:


class MyClass
  {
      int a = 0;
      int b = 0;
      int c = 0;

      MyClass(int a) : a(a) {
      }
  }

答案 2 :(得分:1)

在我看来,确保零初始化的最简单方法是添加一个抽象层:

class MyClass
{
    struct
    {
        int a;
        int b;
        int c;
    } data{};
public:
    MyClass(int a) : data{a} {}
};

将数据成员移动到结构中允许我们使用值初始化来执行零初始化。当然,访问这些数据成员现在更加麻烦:data.a而不仅仅是a中的MyClass。 由于MyClass的支撑初始值设定项,data的默认构造函数将对data及其所有成员执行零初始化。另外,我们可以在MyClass的构造函数中使用聚合初始化,它还对那些未显式初始化的数据成员进行值初始化。

使用继承而不是聚合可以克服数据成员间接访问的缺点:

struct my_data
{
    int a;
    int b;
    int c;
};

class MyClass : private my_data
{
    MyClass() : my_data() {}
public:
    MyClass(int a) : MyClass() { this->a = a; }
};

通过显式指定base-initializer my_data(),也会调用value-initialization,从而导致零初始化。此默认构造函数应该标记为constexprnoexcept。请注意,它不再是微不足道的。我们可以使用初始化而不是使用聚合初始化或转发构造函数进行赋值:

class MyClass : private my_data
{
public:
    MyClass(int a) : my_data{a} {}
};

您还可以编写一个确保零初始化的包装器模板,在这种情况下认为该好处是有争议的:

template<typename T>
struct zero_init_helper : public T
{
    zero_init_helper() : T() {}
};

struct my_data
{
    int a;
    int b;
    int c;
};

class MyClass : private zero_init_helper<my_data>
{
public:
    MyClass(int a) { this->a = a; }
};

拥有用户提供的构造函数,zero_init_helper不再是聚合,因此我们不能再使用聚合初始化。要在MyClass的ctor中使用初始化而不是赋值,我们必须添加转发构造函数:

template<typename T>
struct zero_init_helper : public T
{
    zero_init_helper() : T() {}

    template<typename... Args>
    zero_init_helper(Args&&... args) : T{std::forward<Args>(args)...} {}
};

class MyClass : private zero_init_helper<my_data>
{
public:
    MyClass(int a) : zero_init_helper(a) {}
};

约束构造函数模板需要一些is_brace_constructible特征,这不是当前C ++标准的一部分。但对于这个问题,这已经是一个非常复杂的解决方案了。


也可以按如下方式实现选项#1:

class MyClass
{
  int a;
  int b;
  int c;

  MyClass() = default; // or public, if you like

public:
  MyClass(int a)
  {
    *this = MyClass{}; // the explicitly defaulted default ctor
                       // makes value-init use zero-init
    this->a = a;
  }
};

构造函数委派怎么样?

class MyClass
{
  int a;
  int b;
  int c;

  MyClass() = default; // or public, if you like

public:
  MyClass(int a) : MyClass() // ctor delegation
  {
      this->a = a;
  }
};

[class.base.init] / 7表明上面的例子应该调用值初始化,这导致零初始化,因为类没有任何user- 提供的默认构造函数[dcl]的.init] /8.2。 clang ++的最新版本似乎零对象初始化,g ++的最新版本没有。我已将此报告为g++ bug #65816

相关问题