Storing a pointer to object returned with NRVO
Asked Answered
E

1

8

If I write a factory method that instantiates an object locally and then returns by value, intending to take advantage of NRVO (as per some of the answers here: c++11 Return value optimization or move?), will a pointer/reference to the local object point to the object that is assigned the return value of the method?

Object ObjectBuilder::BuildObject( void )
{
    Object obj;

    //this->ObjectReference = obj; //Disregard this
    //OR
    this->ObjectPtr = &obj;

    return obj;
}

In use:

ObjectBuilder builder;

Object newObject = builder.BuildObject();

Does builder.ObjectPtr refer to newObject?

Eveliaevelin answered 30/6, 2016 at 13:21 Comment(21)
This is UB, anything might happen.Jonellejones
Seems like a free ticket to UndefinedBehavior Land, even if we consider C++17's guaranteed copy ellision. Even if your function does what you think it would do, how do you guarantee the caller will maintain the lifetime of the object for as long as your ObjectBuilder accesses it?Oliverolivera
With C++17's guaranteed (N)RVO this might actually be sort of valid.Sluggard
@Sluggard The standard only guarantees no copy constructor or move constructor are needed to return an object by value. Not that the address of the local object is the same as the address of the object that will be constructed after the function call. What should it do if the returned object is discarded?Oliverolivera
@Holt Still, what if the returned object is discarded?Oliverolivera
If the returned object is discarded then you get a dangling reference which is useless. The interesting part of the question is if this is valid if the object persists.Sluggard
Hmm, I'm also reading now that NRVO is more of an "allowed" optimisation, rather than a "required" one. I think this is a dead-end no matter how I slice it.Eveliaevelin
@ScottOliver See en.cppreference.com/w/cpp/language/copy_elision.Antimere
If you want to have a single object with multiple references/pointers to it, have the factory store and own the object, and return references to it to the users. Trying to reverse this so one user owns the object and the factory keeps a reference/pointer to it is asking for trouble--the factory can neither know nor control the object's lifetime.Pinky
@Antimere Yeah, the builder needs to have ownership, cheers.Eveliaevelin
this->ObjectReference = obj; is OK since it copies the object (assuming those variables are defined so that it compiles)Bur
@Holt: "In C++17, NRVO will be required in some context" No, it won't. Named return value optimization will not be guaranteed under C++17's rules. The only kind of elision that is guaranteed is based on prvalues, and prvalues cannot be named.Houppelande
@Bur What if ObjectReference is of type std::reference_wrapper<Object>?Oliverolivera
@Bur Sorry, that's meant to be of type Object&Eveliaevelin
@ScottOliver Object& can't be assigned, only constructed. I think that's what M.M was referring toOliverolivera
@ScottOliver then that line will assign to the object currently referenced by the referenceBur
@Oliverolivera You're right, never mind :)Eveliaevelin
@NicolBolas You're right, I overlooked the C++17 details.Antimere
Why is everybody talking about a language rule created six years after the language standard being asked about?Zinck
@LightnessRacesinOrbit C++11 is often used as a generic "modern C++" tag. It's hard to tell which C++ standard OP meant unless they specifically tell us.Oliverolivera
@KABoissonneault: They specifically told us C++11. Twice, in fact (I edited it out of the title as being redundant). Reading "C++11" and thinking "oh, I know, maybe he's using C++17" is insane.Zinck
Z
5

No.

You are storing a dangling pointer.

Your program, when it uses this pointer, will have undefined behaviour and that is that.

No amount of convenient optimisation is going to save you from your fate.

Zinck answered 30/6, 2016 at 13:43 Comment(5)
More like, you are returning a copy and keeping a dangling pointer internallyOliverolivera
This answer doesn't explain why the required (N)RVO does not apply. How is the pointer dangling when it is required by the C++17 standard that "When that local object is constructed, it is constructed directly in the storage where the function's return value would otherwise be moved or copied to."?Sluggard
@Sluggard It is required to be constructed there, but is it required to return the address of the caller's storage when you get the address of the "logically" local object?Oliverolivera
@nwp: Well, for a start, the question is tagged C++11.Zinck
@Oliverolivera I don't know. I would expect an answer to answer that.Sluggard

© 2022 - 2024 — McMap. All rights reserved.