简体   繁体   中英

copy elision of temporary object

CPP Refs states:

— when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

Let's say I have some test code:

#include <iostream>
#include <vector>

using namespace std;

template <typename T>
class MyVector : public vector<T>
{ 
public:
    MyVector()
    {
        cout << "MyVector()" << endl;
    }

    MyVector(const MyVector& right):
        vector<T>(right)
    {
        cout << "MyVector(const MV&)" << endl;
    }

    MyVector(MyVector&& right) :
        vector<T>(right)
    {
        cout << "MyVector(MV&&)" << endl;
    }

};

class A
{
public:
    A() = default;
    A(MyVector<char> vec) :
        _vec(std::move(vec))
    {
        cout << "A(MyVec)" << endl;
    }
private:
    MyVector<char> _vec;
};

MyVector<char> funcElision()
{
    cout << "\nElision" << endl;
    MyVector<char> tmp;
    tmp.emplace_back('a');
    return tmp;
}

A funcElisionExternal()
{
    cout << "\nElision external test" << endl;
    return A(funcElision());
}


A funcElisionInternal()
{
    cout << "Elision internal test" << endl;
    MyVector<char> tmp;
    tmp.emplace_back('a');
    return A(tmp);
}

int main()
{
    auto a = funcElisionInternal();
    auto b = funcElisionExternal();
}

The output of the test is:

Elision internal test
MyVector()
MyVector(const MV&)
MyVector(MV&&)
A(MyVec)

Elision external test

Elision
MyVector()
MyVector(MV&&)
A(MyVec)
 End

The function elisionExternal does work as expected, but i don't know why the elisionInternal is doing the copy operation, since the MyVec is temporary object?

Several things are going on here.

  • funcElision is omitting the copy in its return because of Named Return Value Optimization (NRVO), a special rule for named return values when: "a function returns a class type by value, and the return statement's expression is the name of a non-volatile object with automatic storage duration, which isn't a function parameter, or a catch clause parameter, and which has the same type (ignoring top-level cv-qualification) as the return type of the function."
  • In funcElisionExternal , the return value of funcElision is used as a "nameless temporary", which can specifically elide copies (and moves post-C++11). An A is then constructed and returned using Return Value Optimization (RVO) since it is also a nameless temporary.
  • In funcElisionInternal , tmp is a named temporary, so it can only elide copies with NRVO. However, it is not the value that is being returned, and does not have the same type as the function's return signature - it is passed to A's constructor first. So it cannot use NRVO.

Other rules for copy elision have to do with throw expressions and exceptions, so are not applicable here.

See cppreference's page on copy elision for more.

 return A(tmp); 

A 's constructor that takes a MyVector takes it by value. Therefore, A 's constructor parameter is initialized by copying from the glvalue. There is no possibility of elision here because tmp is not a prvalue; it is an lvalue.

You can only elide from an lvalue if it is being returned directly . That is, if you returned tmp , and the return type was decltype(tmp) , then elision could take place (as you do with funcElision ). But otherwise, no.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM