0

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 expression A() 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 the A() 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
Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
  • 1
    I am still trying to understand you question, maybe this comment from me will help figure that out :) The rule explains that storage allocation and object initialization can be split to avoid making unnecessary copies (and or temporaries). For example for the make function this means that the caller allocates storage for NonMovable and that the make function then initializes it (to avoid, copies/moves etc. Ties in to RVO, copy elision). For NonMoveable x = 5, it means that with this proposal, the "left hand side" allocates, the right hand side initializes without move or copy. – Pepijn Kramer Sep 15 '21 at 08:51
  • @PKramer ‘The rule explains that storage allocation and object initialization can be **split** to avoid making unnecessary copies’ Thanks, I find this description really enlightening. So if I got it right, we consider that object creation = storage allocation + object initialization, i.e. that initialization is the second step of the creation process. This implies that initialization requires storage allocation to create an object, and therefore that a prvalue in isolation does not create an object anymore since it has been redefined as initializing an object. – Géry Ogam Sep 15 '21 at 11:27
  • @PKramer But can’t glvalues also initialize objects? For instance in the definition `int j = i;` the expression `i` is a glvalue, yet it initializes `j`. – Géry Ogam Sep 15 '21 at 11:35
  • There are so many types of initialization I loose track :) Look at the bottom of https://en.cppreference.com/w/cpp/language/default_initialization to see a whole list. For a lot of the initialization methods like the one above I've got kind of a mental picture of what's happening. For the rest I just look things up if they don't behave as I expect. – Pepijn Kramer Sep 15 '21 at 11:45
  • 1
    @PKramer I don't think that, generally, _object creation_ = _storage allocation_ + _object initialization_. According to this: http://eel.is/c++draft/intro.object#1.sentence-2, for instance, _placement new_ creates an object. Which does not involve any storage allocation. The same holds for changing the active _union_ member. – Daniel Langr Sep 15 '21 at 11:56
  • @DanielLangr That's what I mean by having a sort of mental picture, and having to lookup the details when I need them. And placement new in my mind is (mostly) associated with reuse of container memory (and updating a bit of administration), before initialization happens. Anyway been coding C++ since '95 and still learning :) – Pepijn Kramer Sep 15 '21 at 12:06
  • 1
    @Maggyero: I believe the lvalue-to-rvalue conversion is applied in `int j = i;`, although the standard doesn’t seem to say so explicitly; it just says the declared object gets “the (possibly converted) value of the initializer expression)”. That said, initialization of an object of class type need not involve a prvalue at all (*e.g.*, `std::pair(*a,*b)`). – Davis Herring Sep 15 '21 at 13:06
  • @DanielLangr I also thought that object creation = object initialization, until LanguageLawyer and DavisHerring disagreed and I read [this section](https://en.wikipedia.org/wiki/Object_lifetime#Steps) on Wikipedia. One could argue that placement `new` does create an object since it performs the final step (initialization) of the creation process. – Géry Ogam Sep 15 '21 at 15:57

0 Answers0