C++ - 混合使用默认成员初始化和成员初始化列表 - 是否明智?

3
这部分是关于风格和正确性的问题。提交以下样例(一个处理包含嵌入头文件数据块的类的简化版本):
class Foo {
 public:
  Foo(size_t size)
      : scratch_(new uint8_t[header_length_ + size]),
        size_(header_length_ + size) {
  }
  ~Foo() {
    delete[] scratch_;
  }
  Foo(const Foo&) = delete;  // Effective C++
  void operator=(const Foo&) = delete;  // Effective C++
 protected:
  struct Header {
    uint32_t a, b, c, d;
  };
  uint8_t * const scratch_;
  size_t const size_;
  Header * const header_ = reinterpret_cast<Header *>(scratch_);
  static constexpr size_t header_length_ = sizeof(Header);
  static constexpr size_t data_offset_ = header_length_;
  size_t const data_length_ = size_ - data_offset_;
};

首先,技术上的正确性...按照写法,scratch_size_会被先初始化,然后是header_,最后是data_length_吗?(constexpr项目是编译时字面常量,不参与初始化顺序。)同样正确的是,初始化程序如何声明,无论是默认成员初始化(int foo = 5)还是成员初始化列表,都不会影响初始化顺序,而是成员声明的顺序才是重要的吗?我在这个答案中找到了有关初始化顺序的ISO规范,并且我所了解的是,scratch_size_出现在成员初始化列表中与给定默认成员初始化器的其他成员相比并不重要;唯一重要的是scratch_size_在其他成员之前声明。假设如果scratch_size_是最后声明的,则header_data_length_将(不希望/不正确地)首先初始化。
风格问题...混合这两种初始化方式是不好的风格吗?我的方法是,成员初始化列表中的项目(scratch_size_)取决于传递给构造函数的参数,而其余类成员则来自其他类成员。显然,如果初始化程序依赖于构造函数参数,则必须将其放入成员初始化列表中。我是否应该将所有初始化程序都放入成员初始化列表中,并放弃默认成员初始化器?在我看来,这可能会使代码变得更难以理解。您有何想法?

我相信这是正确的...个人认为不太美观,但其他人可能有不同的看法。 - M.M
4
应该写成 delete[] scratch_; - Igor Tandetnik
1
"传统初始化" 默认成员初始化器并没有什么"传统"的。 - Nicol Bolas
1
@DavidR: 是的。 - Nicol Bolas
正确的名称是 brace-or-equal-initializer - M.M
显示剩余3条评论
2个回答

6
默认成员初始化程序的存在不会改变类型的子对象初始化顺序。它将始终按照声明顺序进行。

样式由您决定。您拥有的构造函数越多,使用DMI时获得的好处就越多,因为您不需要重复不变的初始化。同时,如果您开始编写覆盖DMI的构造函数,那么可能会对对象的初始状态产生混淆。关键是尝试不要让人感到意外。

然而,在您特定的情况下,我认为您有太多的变量了。您的数组应该只是一个std::vector<uint8_t>。拥有header_指针是可疑的,但可以辩解(尽管初始化不正确;您需要使用放置new来满足C++的对象模型)。但是data_length_可以根据需要进行计算。

您拥有的成员越少,混淆它们如何被初始化的机会就越少。


我正在学习C++,之前写了20年的嵌入式C,还有一些C#和90年代末的少量C++。非常恰当的观点。我明白DMI和多个构造函数的含义;我也从你给出的一个链接中看到,构造函数的成员初始化将覆盖DMI,这是有道理的。放置new完全合理;它是一种语言正确的方式来进行叠加,而不像我滥用指针。关于太多变量,我可能犯了过早优化的错误;一行函数并不会对性能造成太大的影响。感谢您的帮助。 - Dana M

-1

在所有的论坛中,都建议使用初始化列表来初始化类成员,无论是const还是non-const。在您的情况下可能不是问题,但当该类用于扩展时可能会出现问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接