initializing a non-copyable member (or other object) in-place from a factory function

前端 未结 2 528
醉酒成梦
醉酒成梦 2021-02-04 01:43

A class must have a valid copy or move constructor for any of this syntax to be legal:

C x = factory();
C y( factory() );
C z{ factory() };

In

相关标签:
2条回答
  • 2021-02-04 02:38

    Issues like this were among the prime motivations for the change in C++17 to allow these initializations (and exclude the copies from the language, not merely as an optimization).

    0 讨论(0)
  • 2021-02-04 02:42

    On your main question:

    The question is, how to initialize a nonstatic member from a factory function returning non-copyable, non-moveable type?

    You don't.

    Your problem is that you are trying to conflate two things: how the return value is generated and how the return value is used at the call site. These two things don't connect to each other. Remember: the definition of a function cannot affect how it is used (in terms of language), since that definition is not necessarily available to the compiler. Therefore, C++ does not allow the way the return value was generated to affect anything (outside of elision, which is an optimization, not a language requirement).

    To put it another way, this:

    C c = {...};
    

    Is different from this:

    C c = [&]() -> C {return {...};}()
    

    You have a function which returns a type by value. It is returning a prvalue expression of type C. If you want to store this value, thus giving it a name, you have exactly two options:

    1. Store it as a const& or &&. This will extend the lifetime of the temporary to the lifetime of the control block. You can't do that with member variables; it can only be done with automatic variables in functions.

    2. Copy/move it into a value. You can do this with a member variable, but it obviously requires the type to be copyable or moveable.

    These are the only options C++ makes available to you if you want to store a prvalue expression. So you can either make the type moveable or return a freshly allocated pointer to memory and store that instead of a value.

    This limitation is a big part of the reason why moving was created in the first place: to be able to pass things by value and avoid expensive copies. The language couldn't be changed to force elision of return values. So instead, they reduced the cost in many cases.

    0 讨论(0)
提交回复
热议问题