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()
auto
for Variable DeclarationsOriginally posted as totw/74 on 2014-04-21
By Bradley White ([email protected])
“Delegating work works, provided the one delegating works, too.” – Robert Half
When a class has multiple constructors there is often a need to perform similar
initialization in each variant. To avoid code duplication, many older
classes resort to defining a private SharedInit()
method that is called from
the constructors. For example:
class C {
public:
C(int x, string s) { SharedInit(x, s); }
explicit C(int x) { SharedInit(x, ""); }
explicit C(string s) { SharedInit(0, s); }
C() { SharedInit(0, ""); }
private:
void SharedInit(int x, string s) { … }
};
C++11 provides a new mechanism, delegating constructors, for dealing with such situations more clearly by allowing one constructor to be defined in terms of another. It is also an efficiency gain if the class has members that are expensive to default-initialize.
class C {
public:
C(int x, string s) { … }
explicit C(int x) : C(x, "") {}
explicit C(string s) : C(0, s) {}
C() : C(0, "") {}
};
Note that if you delegate to another constructor you cannot also use a member initialization list – all initialization is done by the delegated constructor. Don’t go overboard though. If all the shared code does is set members, separate member-initialization lists or in-class initializers are probably clearer than using delegating constructors. Use good judgement.
Aside: an object is not considered complete until the delegating constructor returns; in practice, this only matters if the constructors can throw, as they leave the delegated-from objects in an incomplete state.
Another, less common form of constructor code duplication occurs when extending the behavior of a multi-constructor class through a wrapper. For example, consider a “veneer” subclass of C that just adds a new member function.
class D : public C {
public:
void NewMethod();
};
But what of the constructors for D? We’d like to simply re-use those from C rather than writing out all the forwarding boilerplate, and C++11 allows for this via the new inheriting constructors mechanism.
class D : public C {
public:
using C::C; // inherit all constructors from C
void NewMethod();
};
This new form of “using” for constructors matches its previous use for member functions.
Note, however, that constructors should really only be inherited when the derived class does not add new data members that need to be initialized explicitly. Indeed, the style guide cautions against inheriting constructors unless the new members (if any) have in-class initialization.
So, go ahead and use C++11’s delegating and inheriting constructors when they reduce duplication, eliminate forwarding boilerplate, or otherwise make your classes simpler and clearer.