【发布时间】:2016-12-30 05:18:29
【问题描述】:
这部分是风格问题,部分是正确性问题。提交以下示例(处理包含嵌入标头的数据块的类的精简版):
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)还是成员初始化器列表,对初始化顺序没有影响,但重要的是声明成员的顺序?我找到了this answer,引用了关于初始化顺序的ISO规范,我收集到的是scratch_和size_出现在成员初始化列表中,而不是其他被赋予默认成员初始化器的成员,这并不重要;重要的是 scratch_ 和 size_ 在其他成员之前声明。据推测,如果 scratch_ 和 size_ 是最后声明的,那么 header_ 和 data_length_ 将(不希望地/不正确地)首先被初始化。
风格问题...混合这两种初始化风格是不是很糟糕?我的方法是成员初始化列表中的项目(scratch_、size_)取决于传递给构造函数的参数,而其余的类成员则派生自其他类成员。显然,如果初始化器依赖于构造函数参数,那么它必须进入成员初始化列表。我是否应该将 all 初始化器放入成员初始化列表中,并放弃默认成员初始化器? IMO,这可能会使代码更难遵循。想法?
【问题讨论】:
-
我认为是正确的..个人觉得不是很美,但其他人可能会有所不同
-
应该是
delete[] scratch_; -
"传统初始化" 默认成员初始化器没有什么“传统”。
-
@NicolBolas - 与成员初始化列表中的项目相比,我一直在努力想出一个规范的名称。那么“默认成员初始化器”应该叫它们吗?
-
@DavidR: Yes.
标签: c++ c++11 member-initialization