This section of Richard Smith’s paper Guaranteed copy elision through simplified value categories makes an important distinction between object creation and object initialization (prvalues were defined in C++11 as creating temporary objects or values; they are redefined here in C++17 as initializing objects or values):
Implications of refined value categories
Now we have a simple description of value categories, we can reconsider how expressions in those categories should behave. In particular, given a class type
A
, the expressionA()
is currently specified as creating a temporary object, but this is not necessary: because the purpose of a prvalue is to performs initialization, it should not be the responsibility of theA()
expression to create a temporary object. That should instead be performed by the context in which the expression appears, if necessary. However, in many contexts, it is not necessary to create this temporary object. For instance:// make() is a prvalue (it returns "by value"). Therefore, it models the // initialization of an object of type NonMoveable. NonMoveable make() { // The object initialized by 'make()' is initialized by the following // constructor call. return NonMoveable(42); } // Use 'make()' to directly initialize 'nm'. No temporary objects are created. auto nm = make(); NonMoveable x = {5}; // ok today NonMoveable x = 5; // equivalent to NonMoveable x = NonMoveable(5), // ill-formed today (creates a temporary but can't move it), // ok under this proposal (does not create a temporary object)
We conclude that a prvalue expression of class or array type should not create a temporary object. Instead, the temporary object is created by the context where the expression appears, if it is necessary. The contexts that require a temporary object to be created ("materialized") are as follows:
- when a prvalue is bound to a reference
- when member access is performed on a class prvalue
- when array subscripting is performed on an array prvalue
- when an array prvalue is decayed to a pointer
- when a derived-to-base conversion os performed on a class prvalue
- when a prvalue is used as a discarded value expression
Note that the first rule here already exists in the standard, to support prvalues of non-class, non-array type. The difference is that, with the proposed change, the language rules are now uniform for class and non-class types.
What is the difference between object creation and object initialization in C++?
I have always thought that they were synonymous and had this object model in mind:
|------------|--|----------------|----------|--------------|--|--------------|
<----------> <--------------> <--------> <------------> <------------>
storage object object object storage
allocation initialization lifetime finalization deallocation
<---------------------------------------------->
storage duration