July 18th, 2024

What to do if you don't want a default constructor?

The blog post discusses the implications of not having a default constructor in C++, highlighting design considerations and technical challenges. Solutions like dummy values, std::optional, and std::variant are proposed to address initialization issues.

Read original articleLink Icon
What to do if you don't want a default constructor?

In the blog post "What to do if you don't want a default constructor?" by Sandor Dargo, the author discusses the implications of not having a default constructor in C++. The article explores the concept of default constructors, their necessity from a design perspective, and the technical challenges that arise when they are absent. The author provides examples illustrating difficulties in using standard library types like std::vector or std::map without a default constructor. Various solutions are proposed, such as defining a default constructor with dummy values, using std::optional to wrap objects, or employing std::variant for more complex scenarios. The post emphasizes the importance of considering object initialization and invalid states when designing classes without default constructors. Overall, the article offers insights into handling situations where default constructors are not desired in C++ programming.

Link Icon 6 comments
By @comex - 3 months
It’s nice to make invalid states unrepresentable. Unfortunately, you can’t do that in C++ if you have a move constructor. C++ moves have to leave the source object in a valid state, since the object can still be accessed afterwards and will still have its destructor run. But unless your move is really just a copy, that state has to be some kind of default, or at least semantically meaningless. And if a valid but semantically meaningless state exists, arguably you might as well use it for the default constructor too.
By @WalterBright - 3 months
I've never liked default constructors when it produces something that is not representable without executing code. D does not have default constructors. What one does is specify the statically initialized field values (or leave the fields to be set to their statically initialized value). I.e. it has a default initializer.

What this means in practice is one never is presented with an uninitialized or partially initialized struct. A non-default constructor gets handed a default initialized struct to start with. This makes for more reliable software. (Double initialization can be removed by the optimizer.)

Why D doesn't have default constructors gets brought up now and then, as it is an unusual choice.

By @advael - 3 months
A pattern I've seen some people do is to just make an operator bool for the type that checks for a contextually-sensical invalid state that is also the default constructed state. This is absolutely a hack, and has lots of other implications, and I wouldn't recommend it, but I see why people do it, because it creates a low-overhead way of getting around the possibility of invalid stuff while not taking on the problems of lacking a default constructor

Personally, I like the simplicity of this kind of approach, but prefer to force consumers of the type to be more explicit. To that end, I really like having an constexpr bool operator! instead, so the same checks can be performed without making it easy to accidentally coerce your type into some shady arithmetic operations. You still can if you meant to, but it will be more obvious what you're doing and won't happen accidentally

By @masfuerte - 3 months
operator<=> was new to me. It's the three-way comparison operator.

https://en.cppreference.com/w/cpp/language/operator_comparis...

By @szundi - 3 months
-O7 ?