Do C++ compilers avoid copying when returning by value?

断了今生、忘了曾经 提交于 2019-12-11 06:42:47

问题


Consider the following code:

LargeObject getLargeObject()
{
    LargeObject glo;
    // do some initialization stuff with glo
    return glo;
}

void test()
{
    LargeObject tlo = getLargeObject();
    // do sth. with tlo;
}

A simple compiler would create a local LargeObject glo on the getLargeObject() stack and then assign it to tlo in test() when returning, which involves a copy operation.

But shouldn't a clever compiler realize that glo is going to be assigned to tlo and thus just use tlo's memory in the first place to avoid the copy operation? Resulting in something (functionally) like:

void getLargeObject(LargeObject &lo)
{
    // do init stuff
}

void test()
{
    LargeObject lo;
    getLargeObject(lo);
}

My guess is, that compilers do something similar. But can it always be done? Are there situations where it can't be optimized like that? How can I know if my return value is copied or not?


回答1:


Your guess is correct. And yes, there are situations where it cannot be done, for example:

LargeObject getLargeObject()
{
    LargeObject glo1, glo2;
    // do some initialization stuff         
    if (rand() % 2)
        return glo1;
    return glo2;
}

It can't be done there because the compiler can't know whether it will use glo1 or glo2 for the return value.

"How can I know if my return value is copied or not?"

Two ways I can think of. You could create noisy copy constructors. That is, copy constructors that have some detectable side effect, like printing a message. Then of course there's the old look at the assembly.




回答2:


Yes it should. This is called the named returned value optimization (NRVO or just RVO).




回答3:


For starters, even a naïve compiler will not “assign to tlo”, since the standard doesn't allow it. The formal semantics of your code involves two copies (both using the copy constructor); the first from glo to a temporary return value, and the second from this temporary return value to tlo. The standard, however, formally gives compilers the right to eliminate both of these copies, in this specific case, and practically speaking, I imagine that all compilers do.

The first copy can be suppressed anytime you return a local variable or a temporary; some compilers don't do it if there is more than one return in the code, however (but that will never be the case in well written code).

The suppression of the second copy depends on the fact that you are constructing a new object at the call site. If you're not constructing a new object, then there may not even be a second copy to suppress; e.g. in a case like getLargeObject().memberFunction(). If you're assigning to an existing object, however, there's not much the compiler can do; it must call the assignment operator. If the assignment operator copies, then you get that copy.



来源:https://stackoverflow.com/questions/8228759/do-c-compilers-avoid-copying-when-returning-by-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!