string_view
operator+
vs. StrCat()
absl::Status
std::bind
absl::optional
and std::unique_ptr
absl::StrFormat()
make_unique
and private
Constructors.bool
explicit
= delete
)switch
Statements Responsibly= delete
AbslHashValue
and Youcontains()
std::optional
parametersif
and switch
statements with initializersinline
Variablesstd::unique_ptr
Must Be MovedAbslStringify()
vector.at()
Originally posted as Totw #61 on Nov 12, 2013
by Michael Chastain ([email protected])
Updated October, 2016
A default member initializer declares a default value for a member upon construction and looks like this:
class Client {
private:
int chunks_in_flight_ = 0;
};
This default initializer propagates into all constructors for that class, even
constructors that C++ synthesizes. Initializing members in this way is useful
for classes with lots of data members, especially for types such as bool
,
int
, double
, and raw pointers. Non-static data members of these fundamental
types often slip through the cracks and end up uninitialized. Non-static data
members of any type may have initializers, though.
Default member initializers are also useful for declarations of simple structs with no user-written constructor:
struct Options {
bool use_loas = true;
bool log_pii = false;
int timeout_ms = 60 * 1000;
std::array<int, 4> timeout_backoff_ms = { 10, 100, 1000, 10 * 1000 };
};
If a class constructor initializes a data member that already has a default initializer, the initializer in the constructor supersedes the default:
class Frobber {
public:
Frobber() : ptr_(nullptr), length_(0) { }
Frobber(const char* ptr, size_t length)
: ptr_(ptr), length_(length) { }
Frobber(const char* ptr) : ptr_(ptr) { }
private:
const char* ptr_;
// length_ has a non-static class member initializer
const size_t length_ = strlen(ptr_);
};
This code is equivalent to the older code:
class Frobber {
public:
Frobber() : ptr_(nullptr), length_(0) { }
Frobber(const char* ptr, size_t length)
: ptr_(ptr), length_(length) { }
Frobber(const char* ptr)
: ptr_(ptr), length_(strlen(ptr_)) { }
private:
const char* ptr_;
const size_t length_;
};
Note that the first and second Frobber
constructors have initializers for
their non-static variables; these two constructors will not use the default
initializer for length_
. The third Frobber
constructor, however, does
not have an initializer for length_
so this constructor will use the default
initializer for length_
.
As always in C++, all non-static variables are initialized in the order of their declaration.
In the first 2 of the 3 Frobber
constructors, the constructor provides an
initializer for length_
. The constructor initializer supersedes the default
member initializer – the non-static class member initializer does not
contribute to code generation for these constructors.
Note: Older documentation may refer to default member initializers as non-static data member initializers, abbreviated to NSDMIs.
Default member initializers won’t make your program any faster. They will help reduce bugs from omissions, especially when someone adds a new constructor or a new data member.
Be careful not to confuse a non-static class member initializer with a static class member initializer:
class Alpha {
private:
static int counter_ = 0;
};
This is an older feature. counter_
is static and this is a static declaration
with an initializer. This is different from a non-static class member
initializer, just as static member variables are different from non-static
member variables.