这部分是风格问题,部分是正确性问题。提交以下示例(处理包含嵌入标头的数据块的类的精简版):
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_
andsize_
是最后声明的,那么header_
anddata_length_
将(不希望地/不正确地)首先被初始化。
风格问题...混合这两种初始化风格是不是很糟糕?我的方法是成员初始化列表 ( scratch_
, size_
) 中的项目取决于传递给构造函数的参数,而其余的类成员则派生自其他类成员。显然,如果初始化器依赖于构造函数参数,那么它必须进入成员初始化列表。我是否应该将所有初始化程序都放入成员初始化列表中,并放弃默认成员初始化程序?IMO,这可能会使代码更难遵循。想法?