This is partly a style question, partly a correctness question. Submit the following sample (a strip-down of a class which deals with a block of data that contains an embedded header):
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_;
};
First, technical correctness... is it correct that as written, scratch_
and size_
will be initialized first, then header_
, then data_length_
? (constexpr
items are compile-time literal constants and don't figure into initialization order.) Is it also correct that how the initializer is declared, be it traditional int foo = 5
initialization or a member initializer list, has no impact on initialization order, but rather, what matters is solely the order in which members are declared? I found this answer, citing the ISO spec regarding initialization order, and what I gathered is that it's unimportant that scratch_
and size_
appear in the member initialization list versus other members that are given traditional initializers; it only matters that scratch_
and size_
are declared before the other members. Presumably if scratch_
and size_
were declared last, then header_
and data_length_
would (undesirably/incorrectly) be initialized first.
Style question... is it bad style to mix these two initialization styles? My approach is that items in the member initialization list (scratch_
, size_
) depend on the argument(s) passed into the constructor, while the remaining class members are derived from other class members. Obviously, if an initializer depends on a constructor argument, then it has to go into a member initialization list. Should I throw all initializers into the member initialization list regardless, and abandon traditional initialization? IMO, that may make the code a little harder to follow. Thoughts?
Aucun commentaire:
Enregistrer un commentaire