C++11 如何确保对象已初始化为零?

C++11 如何确保对象已初始化为零?,c++11,initialization,zero,default-constructor,value-initialization,C++11,Initialization,Zero,Default Constructor,Value Initialization,更新:我想看看是否有一种方法可以立即对整个类进行零初始化,因为从技术上讲,人们可能会忘记在每个成员之后添加“=0”或“{}”。其中一条注释提到,显式默认的no arg c-tor将在表单MyClass c{};的值初始化期间启用零初始化;。看看这些,我很难弄清楚哪一条语句具体说明了这一点 初始化现在是一个复杂的话题,因为C++11已经改变了各种初始化结构的含义和语法。我无法从其他问题中收集到足够好的信息。但请看,例如 我所面临的具体问题是:我想确保我的类的成员在声明默认c-tor的1个类和不声明

更新:我想看看是否有一种方法可以立即对整个类进行零初始化,因为从技术上讲,人们可能会忘记在每个成员之后添加“=0”或“{}”。其中一条注释提到,显式默认的no arg c-tor将在表单MyClass c{};的值初始化期间启用零初始化;。看看这些,我很难弄清楚哪一条语句具体说明了这一点

初始化现在是一个复杂的话题,因为C++11已经改变了各种初始化结构的含义和语法。我无法从其他问题中收集到足够好的信息。但请看,例如

我所面临的具体问题是:我想确保我的类的成员在声明默认c-tor的1个类和不声明默认c-tor的2个类中都被调零

对于2,使用{}初始化可以完成这项工作,因为这是值初始化的语法,它转换为零初始化,或者如果类是聚合的,则转换为聚合初始化—在这种情况下,没有为所有成员提供初始化器!初始化为零

但是对于我来说,我仍然不确定什么是最好的方法。从我收集的所有信息中,我了解到,如果您提供一个默认的c-tor,例如,将某些成员设置为某些值,则必须显式地将剩余成员归零,否则语法MyClass c=MyClass;或者C++11MyClass C{};他不会做这项工作。换句话说,在这种情况下,值初始化意味着只需调用您的c-tor,这就是不归零

如果您声明一个接受值的c-tor,并将这些值设置为成员的子集,那么您也会遇到同样的情况,但您希望其他成员为零ed:没有简写法可以这样做-我考虑3个选项:

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

  MyClass(int a)
  {
    this->a = a;
    // now b and c have indeterminate values, what to do? (before setting 'a')


    // option #1
    *this = MyClass{}; // we lost the ability to do this since it requires default c-tor which is inhibited by declaring this c-tor; even if we declare one (private), it needs to explicitly zero members one-by-one

    // option #2
    std::memset(this, 0, sizeof(*this)); // ugly C call, only works for PODs (which require, among other things, a default c-tor defaulted on first declaration)

    // option #3
    // don't declare this c-tor, but instead use the "named constructor idiom"/factory below
  }


  static MyClass create(int a)
  {
    MyClass obj{}; // will zero-initialize since there are no c-tors
    obj.a = a;
    return obj;
  }
};
我的推理正确吗?
您会选择3个选项中的哪一个?

如何使用类内初始化

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

使用类内初始化怎么样

class Foo
{
    int _a{}; // zero-it
    int _b{}; // zero-it
public:
    Foo(int a): _a(a){} // over-rules the default in-class initialization
};
备选案文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) {
      }
  }
备选案文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) {
      }
  }

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

class MyClass
{
    struct
    {
        int a;
        int b;
        int c;
    } data{};
public:
    MyClass(int a) : data{a} {}
};
将数据成员移动到结构中可以使用值初始化来执行零初始化。当然,现在访问这些数据成员有点麻烦:data.a,而不仅仅是MyClass中的a。 MyClass的默认构造函数将对数据及其所有成员执行零初始化,因为数据的初始值设定项是大括号的。此外,我们可以在MyClass的构造函数中使用聚合初始化,它还可以对未显式初始化的数据成员进行值初始化

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

通过显式指定基初始值设定项my_data,也会调用值初始化,从而导致零初始化。此默认构造函数可能应标记为constexpr和noexcept。请注意,它不再是微不足道的。通过使用聚合初始化或转发构造函数,我们可以使用初始化而不是赋值:

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; }
};
约束构造函数模板需要一些iSuthReabeBug构造的特性,而不是当前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建议上面的示例调用值初始化,这将导致零初始化,因为该类没有任何用户提供的默认构造函数[dcl.init]/8.2。clang++的最新版本似乎对对象进行零初始化,而g++的最新版本则没有。我将此报告为。

以我的拙见,确保零初始化的最简单方法是添加一层抽象:

class MyClass
{
    struct
    {
        int a;
        int b;
        int c;
    } data{};
public:
    MyClass(int a) : data{a} {}
};
将数据成员移动到结构中可以使用值初始化来执行零初始化。当然,现在访问这些数据成员有点麻烦:data.a,而不仅仅是MyClass中的a。 MyClass的默认构造函数将对数据及其所有成员执行零初始化,因为数据的初始值设定项是大括号的。此外,我们可以在MyClass的构造函数中使用聚合初始化,它还可以对未显式初始化的数据成员进行值初始化

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

通过显式指定基初始值设定项my_data,也会调用值初始化,从而导致零初始化。此默认构造函数可能应标记为constexpr和noexcept。请注意,它不是lon 这是微不足道的。通过使用聚合初始化或转发构造函数,我们可以使用初始化而不是赋值:

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; }
};
约束构造函数模板需要一些iSuthReabeBug构造的特性,而不是当前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建议上面的示例调用值初始化,这将导致零初始化,因为该类没有任何用户提供的默认构造函数[dcl.init]/8.2。clang++的最新版本似乎对对象进行零初始化,而g++的最新版本则没有。我将此报告为。

classmyclass{inta=0;intb=0;intc=0;/*您的构造函数*/};。这甚至可以是自C++14以来的聚合。即使我们声明一个私有,它也需要逐个显式地归零成员,而不是如果您将其默认为默认值。@dyp据我所知,默认的no arg C-tor不会归零成员?@haelix是,但它允许值初始化执行零初始化。也就是说,MyClass obj{};如果MyClass的默认构造函数是默认的,则零将初始化obj。是的,在委托给默认构造函数时,构造函数委托似乎不会调用值初始化,而只是调用该构造函数。但是,您可以通过添加一个抽象层来实现类似的功能,即类MyClass{struct{inta;intb;intc;}data;public:MyClass=default;MyClassint a:data{data.a=a;};类MyClass{inta=0;intb=0;intc=0;/*您的构造函数*/};。这甚至可以是自C++14以来的聚合。即使我们声明一个私有,它也需要逐个显式地归零成员,而不是如果您将其默认为默认值。@dyp据我所知,默认的no arg C-tor不会归零成员?@haelix是,但它允许值初始化执行零初始化。也就是说,MyClass obj{};如果MyClass的默认构造函数是默认的,则零将初始化obj。是的,在委托给默认构造函数时,构造函数委托似乎不会调用值初始化,而只是调用该构造函数。但是,您可以通过添加一个抽象层来实现类似的功能,即类MyClass{struct{inta;intb;intc;}data;public:MyClass=default;MyClassint a:data{data.a=a;};非常详细的回答,谢谢。也许有人会对最后一段构造函数委托添加更多有用的想法-这在语法上是最好的方法,也是我认为标准应该提供的东西。@haelix我提交了一份g++错误报告。非常详细的回答,谢谢。也许有人会对最后一段构造函数委托添加更多有用的想法-这在语法上是最好的方法,我相信该标准应该提供。@haelix我提交了一份g++错误报告。