1

更新:我正在寻找是否有一种方法可以一次将整个类初始化为零,因为从技术上讲,人们可能会忘记在每个成员之后添加一个 ' = 0' 或 ' '。{}其中一条评论提到,显式默认的无参数 c-tor 将在表单的值初始化期间启用MyClass c{};零初始化。查看http://en.cppreference.com/w/cpp/language/value_initialization我无法确定哪些语句指定了这一点。

初始化现在是一个复杂的话题,因为 C++11 已经改变了各种初始化结构的含义和语法。我无法从其他问题中收集到足够好的信息。但是,例如,请参阅编写默认构造函数强制零初始化?.

我面临的具体问题是:我想确保我的类的成员对于 (1) 声明默认 c-tor 的类和 (2) 没有声明默认 c-tor 的类都清零。

对于 (2),初始化 with{}完成了这项工作,因为它是值初始化的语法,它转换为零初始化,或者如果您的类是聚合的,则聚合初始化 - 在没有提供初始化程序的成员的情况下(全部! ) 是零初始化的。

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

如果您声明一个接受值的 c-tor 并将这些值设置为成员的子集,您会遇到同样的情况,但您希望其他成员为零:没有简写方式 - 我正在考虑 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 个选项中的哪一个?

4

3 回答 3

4

使用类内初始化怎么样?

class Foo
{
    int _a{}; // zero-it
    int _b{}; // zero-it
public:
    Foo(int a): _a(a){} // over-rules the default in-class initialization
};
于 2015-04-02T12:44:28.190 回答
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) {
      }
  }
于 2015-04-02T12:46:17.273 回答
1

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

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

将数据成员移动到结构中让我们可以使用值初始化来执行零初始化。当然,现在访问这些数据成员有点麻烦:data.a而不仅仅是aMyClass. 的默认构造函数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(),也会调用值初始化,从而导致零初始化。这个默认构造函数可能应该被标记为constexprand 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; }
};

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

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 建议上面的示例应该调用值初始化,这会导致零初始化,因为该类没有任何用户提供的默认构造函数 [dcl.init]/8.2。最新版本的 clang++ 似乎对对象进行了零初始化,而最新版本的 g++ 则没有。我已将此报告为g++ bug #65816

于 2015-04-14T15:56:58.270 回答