Sayeth the C++ standard:
The point of declaration for a name is immediately after its complete declarator and before its initializer (if any)... [basic.scope.pdecl]
That is, a variable is in scope, and can be referred to, in the context of its own initialization expresion.
As far as I can tell, you can do the following types of things with it:
int x = x
, which is well-formed but meaningless.void* p = &p
, which is cute but useless.std::any a {&a}
, the C++17 version of #2.MyClass m {std::move(m)}
, the C++11 version of #1 and probably UB somehow.MyClass m {myFunc(m)}
, with a function which takes your uninitialized object, I guess records it somewhere? and returns some value back so the constructor can have a go.#1-4 are useless, of course. It seems like one could construct an interface where #5 made some sense, but I can't see it being the most straightforward way of accomplishing anything. Since the new variable is not yet initialized when the initializer is evaluated, it's useless/illegal to read its value, and its address isn't generally going to be important to its initialization.
(One could make a slightly stronger case for leaving the point of declaration until after the initializer: int avg = avg(a,b,c)
. That's not good code, and it's not essential for anything, but it would make more sense than void* p = &p
.)
But it's not just about use cases. In general, C++ takes pains to prevent access to an uninitialized object. For instance, it sets up an object's vtable one base class at a time: if D inherits from C inherits from B, during C's constructor virtual methods will be dispatched to C's implementations, not D's. The common situations where one can peek at an uninitialized object are this situation, and (more commonly problematic) the use of this
in a member initializer expression.
So I can't see a use for bringing a name in scope before its initializer, and I can see a clear rationale (which Stroustrup would also have seen) for delaying it until after the initializer. Given that, is there a clear point to C++'s chosen behavior?
Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.
There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.
What is the difference between initialization and assignment? Initialization gives a variable an initial value at the point when it is created. Assignment gives a variable a value at some point after the variable is created.
its address isn't generally going to be important to its initialization.
template <class T>
struct Node
{
Node *prev, *next;
std::optional<T> data;
};
template <class T>
struct List
{
Node<int> sentinel {&sentinel, &sentinel};
// methods ...
};
This is a totally legitimate and useful initialisation of a sentinel-based doubly linked list.
Any graph-like data structure can have self references, which can be implemented by passing pointers or references to an objects as parameters to its own constructor. There is no reason to disallow those.
If you are worried about undefined behaviour inherent in int x = x;
, just enable warnings (warning: shameless plug) as you should have done anyway. Compilers are now reasonably good at catching this stuff.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With