It seems empirically that C++ always prefers a list initializer over a value initializer. My question is thus how can I force value initialization of a type that also supports a direct list initialization. Here is a minimal non-working example:
#include <initializer_list>
using namespace std;
struct foo {
foo(int) {}
foo(initializer_list<char>) {}
};
struct bar {
foo f{256};
};
In this example, I would like f to be initialized using the constructor foo(int) rather than the foo(initializer_list<char>). However, both GCC and Clang reject the code because 256 is too big for a char, which means the C++ spec requires choosing the list initializer. Obviously commenting out the second constructor of foo fixes the problem. What's the easiest way to define bar so as to use value initialization on field f? Ideally I could avoid copy initializing f, because in my real example there is no copy constructor.
update
To clarify: of course it's possible to initialize f explicitly in every single constructor of bar. But my question is specifically about the member initialization syntax because in situations with huge numbers of constructors it is preferable just to initialize certain fields in one place rather than to copy the code all over.
So long as you require foo to be non copyable/moveable, and you require foo to have an initializer_list constructor that could be used instead of a constructor, this is the behavior you get. Therefore, you have to change one of these facts if you want to solve this problem.
If you cannot change the definition of foo at all, then you're screwed. Complain to whomever owns the class.
The second fact is probably the easiest to change, but even that will not be without consequences:
struct il {};
struct foo {
foo(int) {}
foo(il, initializer_list<char>) {}
};
This completely disambiguate the problem. foo{256} will always call the single-integer constructor. However, foo technically has no initializer_list constructors; you instead must use the tag type il to call it with an initializer list of values:
foo f{il{}, {/*actual list*/}};
This requires more braced, but there is no real alternative.
Note that in C++17, guaranteed elision lets you do this:
struct bar {
foo f = foo(256);
};
Regardless of whether foo is mobile or not.
Related
P1008 ("Prohibit aggregates with user-declared constructors") has become part of the C++20 standard, in order to prevent surprising behavior when using aggregate initialization:
struct X {
int i{42};
X() = delete;
};
int main() {
X x2{3}; // Compiles in C++17, error in C++20
}
I agree that the above X x2{3}; statement should not compile. However, all the examples justifying P1008 that I've encountered are not realistic at all - they are purely syntactical and basically meaningless foo/bar/baz code snippets.
What problem does P1008 solve in practice? I find it hard to imagine how I would end up writing something like the above X in a real program.
Deleting the default constructor in a C++17 aggregate without providing other constructors to initialize it seems unrealistic to me.
The most obvious case is this:
struct X
{
private:
X() = default;
};
X x{};
This is not a type which should be able to be initialized outside of a privately accessible context. But it can be.
Now, such types might seem silly, but they're actually useful for implementing private functions that work through forwarding functions. make_shared for example cannot call constructors declared private, even if you make the make_shared template a friend. So instead, you make the constructors public, but require that the user pass an instance of a type that can only be constructed by someone with private access. So X would either be a member type of the target class or X would make the target class a friend.
I looked at a piece of code and I am trying to understand how it works and so here is a minimal working example
template <typename T>
class A
{
public:
A() : _mem(T()) {};
private:
T _mem;
};
The first thing I was not exactly clear about is the initialisation of _mem in the initialiser list. What is this technique(?) called? If I look in the debugger _mem is set to 0. If there is a c++11 way to do the same thing could I receive some comments on that?
This is just to safeguard against an uninitialized A::_mem when T is a POD type or a built-in type (like an int). Using a constructor initializer list of : _mem(T()) will default construct a T and initialize _mem with it. For example:
struct POD {
int num;
};
// ...
A<POD> a;
Here, a._mem would be unitialized (in this case, this means a._mem.num is unitialized.) The : _mem(T()) prevents that from happening and will initialize a._mem.num to 0.
However, since C++11 you can just use inline initialization instead:
template <typename T>
class A {
public:
A() {};
private:
T _mem{};
};
T _mem{}; will default-construct _mem, which in turn means POD::num will be default-constructed, which for an int means it will be zero-initialized.
If this has a name, I don't know it.
What's happening:
T() constructs a temporary T and Zero Initializes it.
_mem(T()) makes _mem a copy of the temporary T. Note: A modern compiler will almost certainly elide the copy and simply zero initialize _mem. This still requires that T be copy-or-moveable, so _mem(T()) and _mem() are not exactly the same.
The only relevant C++ 11 difference I can think of is you can use curly braces, _mem{T{}}, for List Initialization. Not useful here, but very useful in other circumstances.
Triggered by this answer I was reading in the core guidelines:
C.45: Don’t define a default constructor that only initializes data
members; use in-class member initializers instead
The reasoning given is
Reason
Using in-class member initializers lets the compiler generate the
function for you. The compiler-generated function can be more
efficient.
Note that this is specifically about a default constructor that does nothing but initialize the members and the guideline suggests that one should not write such a constructor.
The "bad" example is:
Example, bad
class X1 { // BAD: doesn't use member initializers
string s;
int i;
public:
X1() :s{"default"}, i{1} { }
// ...
};
The "good" example is using in-class member initializers and no user declared constructor:
Example
class X2 {
string s = "default";
int i = 1;
public:
// use compiler-generated default constructor
// ...
};
What can the compiler generated constructor do more efficient than the user-provided one in that particular example (or in any other example)?
Is the initializer list not giving the same opportunities for optimization as in-class initializers?
Short Answer
A defaulted constructor should have the same generated assembly as the equivalent initializer constructor provided that the author includes the correct constexpr and noexcept statuses.
I suspect the "can be more efficient" is referring to the fact that, in general, it will generate more optimal code than the equivalent developer-authored one that misses opportunities such as inline, constexpr, and noexcept.
Long Answer
An important feature that defaulted constructors perform is that they interpret and deduce the correct status for both constexpr and noexcept
This is something that many C++ developers do not specify, or may not specify correctly. Since Core Guidelines targets both new and old C++ developers, this is likely why the "optimization" is being mentioned.
The constexpr and noexcept statuses may affect code generation in different ways:
constexpr constructors ensure that invocations of a constructor from values yielded from constant expressions will also yield a constant expression. This can allow things like static values that are not constant to not actually require a constructor invocation (e.g. no static initialize overhead or locking required). Note: this works for types that are not, themselves, able to exist in a constexpr context -- as long as the constexprness of the constructor is well-formed.
noexcept may generate better assembly of consuming code since the compiler may assume that no exceptions may occur (and thus no stack-unwinding code is necessary). Additionally, utilities such as templates that check for std::is_nothrow_constructible... may generate more optimal code paths.
Outside of that, defaulted constructors defined in the class-body also make their definitions visible to the caller -- which allows for better inlining (which, again, may otherwise be a missed-opportunity for an optimization).
The examples in the Core Guidelines don't demonstrate these optimizations very well. However, consider the following example, which illustrates a realistic example that can benefit from defaulting:
class Foo {
int a;
std::unique_ptr<int> b;
public:
Foo() : a{42}, b{nullptr}{}
};
In this example, the following are true:
A construction of Foo{} is not a constant expression
Construction of Foo{} is not noexcept
Contrast this to:
class Foo {
int a = 42;
std::unique_ptr<int> b = nullptr;
public:
Foo() = default;
};
On the surface, this appears to be the same. But suddenly, the following now changes:
Foo{} is constexpr, because std::unique_ptr's std::nullptr_t constructor is constexpr (even though std::unique_ptr cannot be used in a full constant expression)
Foo{} is a noexcept expression
You can compare the generated assembly with this Live Example. Note that the default case does not require any instructions to initialize foo; instead it simply assigns the values as constants through compiler directive (even though the value is not constant).
Of course, this could also be written:
class Foo {
int a;
std::unique_ptr<int> b;
public:
constexpr Foo() noexcept :a{42}, b{nullptr};
};
However, this requires prior knowledge that Foo is able to be both constexpr and noexcept. Getting this wrong can lead to problems. Worse yet, as code evolves over time, the constexpr/noexcept state may become incorrect -- and this is something that defaulting the constructor would have caught.
Using default also has the added benefit that, as code evolves, it may add constexpr/noexcept where it becomes possible -- such as when the standard library adds more constexpr support. This last point is something that would otherwise be a manual process every time code changes for the author.
Triviality
If you take away the use of in-class member initializers, then there is one last worthwhile point mentioning: there is no way in code to achieve triviality unless it gets compiler-generated (such as through defaulted constructors).
class Bar {
int a;
public:
Bar() = default; // Bar{} is trivial!
};
Triviality offers a whole different direction on potential optimizations, since a trivial default-constructor requires no action on the compiler. This allows the compiler to omit any Bar{} entirely if it sees that the object is later overwritten.
I think that it's important to assume that C.45 refers to constants (example and enforcement):
Example, bad
class X1 { // BAD: doesn't use member initializers
string s;
int i; public:
X1() :s{"default"}, i{1} { }
// ... };
Example
class X2 {
string s = "default";
int i = 1; public:
// use compiler-generated default constructor
// ... };
Enforcement
(Simple) A default constructor should do more than just initialize
member variables with constants.
With that in mind, it's easier to justify (via C.48) why we should prefer in-class initializers to member initializers in constructors for constants:
C.48: Prefer in-class initializers to member initializers in
constructors for constant initializers
Reason
Makes it explicit that the same value is expected to be used in all
constructors. Avoids repetition. Avoids maintenance problems. It leads
to the shortest and most efficient code.
Example, bad
class X { // BAD
int i; string s;
int j; public:
X() :i{666}, s{"qqq"} { } // j is uninitialized
X(int ii) :i{ii} {} // s is "" and j is uninitialized
// ... };
How would a maintainer know whether j was deliberately uninitialized
(probably a poor idea anyway) and whether it was intentional to give s
the default value "" in one case and qqq in another (almost certainly
a bug)? The problem with j (forgetting to initialize a member) often
happens when a new member is added to an existing class.
Example
class X2 {
int i {666};
string s {"qqq"};
int j {0}; public:
X2() = default; // all members are initialized to their defaults
X2(int ii) :i{ii} {} // s and j initialized to their defaults
// ... };
Alternative: We can get part of the benefits from default arguments to
constructors, and that is not uncommon in older code. However, that is
less explicit, causes more arguments to be passed, and is repetitive
when there is more than one constructor:
class X3 { // BAD: inexplicit, argument passing overhead
int i;
string s;
int j; public:
X3(int ii = 666, const string& ss = "qqq", int jj = 0)
:i{ii}, s{ss}, j{jj} { } // all members are initialized to their defaults
// ... };
Enforcement
(Simple) Every constructor should initialize every member variable (either explicitly, via a delegating ctor call or via default
construction).
(Simple) Default arguments to constructors suggest an in-class initializer may be more appropriate.
I am trying to understand the following code that I saw today. I already tried to find a related question, but since I have no idea what this feature of C++ is called it is hard to find related posts. A hint on the correct search term might already help me.
struct A
{ int x; };
struct B
{ B(A a) {}; };
int main()
{
B b{ { 5 } }; // works, seems to create a struct A from {5} and pass it to B's constructor
std::make_unique<B>({ 5 }); // doesn't compile
return 0;
}
Why is {5} not used to create a struct A when passed to make_unique but is used this way in the constructor of B?
If B had a second constructor B(int foo) {}; this one would be used instead of the one frome above (at least that is what I found by trial and error). What is the rule to decide if the argument is automatically used to create a struct A or if it is used directly as int in the constructor?
I am using Visual C++ 14.0
Here's a simplified demonstration:
struct X { X(int); };
void foo(X );
template <typename T> void bar(T );
foo({0}); // ok
bar({0}); // error
The issue is that braced-init-lists, those constructs that are just floating {...}s, are strange beasts in C++. They don't have a type - what they mean must be inferred from how they're actually used. When we call foo({0}), the braced-init-list is used to construct an X because that's the argument - it behaves as if we wrote X{0}.
But in bar({0}), we don't have sufficient context to know what to do with that. We need to deduce T from the argument, but the argument doesn't have a type - so what type could we possibly deduce?
The way to make it work, in this context, is to explicitly provide that T:
bar<X>({0}); // ok
or provide an argument that has a type that can be deduced:
bar(X{0}); // ok
In your original example, you can provide the A directly:
make_unique<B>(A{5})
or the B directly:
make_unique<B>(B({5}))
or just use new:
unique_ptr<B>(new B({5}))
or, less preferred and somewhat questionable, explicitly specify the template parameter:
make_unique<B, A>({5});
A constructor with a single non-default parameter (until C++11) that is declared without the function specifier explicit is called a converting constructor. Your A and B are instances of such constructors (this explains, why your first call works fine.) The problem is, that std::make_unique impedes these explicit calls. Anyhow, it might be a good idea, to not trust in these automatic creation in the first place and spent a few chars to show types. This could improve the readability of the code.
I have a simple object that holds some [public] data.
I want to keep my interface clean, so I don't want to pre-/post- fix anything to the names of the publically accessible variables nor to the names of my function arguments.
That said, I ended up doing something like this:
template<typename T> struct Foo
{
explicit Foo(T x) : x(x) // This [i.e., x(x)] seems to be doing the "Right Thing", but is this well defined?
{/* ^
No pre-/post- fixing.
*/
}
T x; // No pre-/post- fixing.
};
Just to reiterate: All I'm asking is whether this is well defined behavior. Not whether I should or shouldn't be doing this...
Thanks.
Yes, that's fine, and perfectly standard.
Local variables always come first in a name lookup, but the x(...) in an initialization list can obviously only refer to member variables [edit:or a base class].
If you didn't use the initialization list, you would have to write:
explicit Foo(T x)
{
this->x = x;
}
Specifically for the initializer list of a ctor, it's well-defined behavior -- since you can only initialize a member or base class, there's no ambiguity between one of those and the name of a parameter.
Under almost any other circumstance, however, you'll create an ambiguity. In particular, your title simply refers to "function" -- and for any function other than the ctor, this won't work. Even inside the body of the ctor, it won't work -- the "special" treatment is purely within the initializer list of a ctor.