C++11 返回值优化、移动语义及函数返回值构造的重载决议

局部变量unique_ptr能否作为返回值

记得自己之前在哪写过一篇返回值优化的博客,翻了半天csdn,居然没找到,也不知道写在哪了。被问到一个unique_ptr 局部变量能不能做返回值的问题,想当然说因为拷贝构造被delete不行,果然我还是unique_ptr 用的不多,只用来pimpl了。想起来真是被自己蠢笑了。在这里插入图片描述

左值、右值、将亡值

先了解一下左右值、将亡值的概念,概念就不抄了

class A {
  public:
    int a;
};
A getTemp()
{
    return A();  //右值
}
A a = getTemp();//a左值,gettemp()返回值右值

可以看到,按照理想情况,我们其实会一次构造加+两次拷贝构造,还有多个临时对象的析构,但是我们只要实际长期使用的只是为了为了构建一个a变量使用而已,花销太大,因此c++11 引入了移动语义以及RVO机制(RVO c++11 编译器都有,但并不是是语言标准强规范,c++17起才在规范做了强制要求),减少无用的拷贝构造和析构。

跑个实际的例程吧

#include 
#include 
using namespace std;

class Test {
public:
    Test() {
        cout << "Create" << endl;
    }
    Test(const Test &o) {
        cout << "Copied" << endl;
    }

    Test(const Test &&o) {
        cout << "Move" << endl;
    }
    ~Test() {
        cout << "Destroy" << endl;
    }
};
Test ReturnRvalue() {
    return Test();  //RVO优化,函数返回值的地址就是test右值分配的地址,没有做赋值及移动拷贝
}

Test ReturnRvalue1() {
    auto temp = Test();
    return temp;    //NRVO优化,函数返回值的地址就是test右值的地址,没有做赋值及移动拷贝
}
void AcceptVal(Test a) {}
void AcceptRef(const Test &a) {}

int main() {
    cout << "pass by value: " << endl;
    AcceptVal(ReturnRvalue());
    cout << "pass by value1: " << endl;
    AcceptVal(ReturnRvalue1());
    cout << "pass by reference: " << endl;
    AcceptRef(ReturnRvalue());
}

输出如下,节省了复制/移动拷贝,只进行了一次构造

pass by value:
Create
Destroy
pass by value1:
Create
Destroy
pass by reference:
Create
Destroy

接下来禁用返回值优化 -fno-elide-constructors (gcc选项,msvc没找到)

pass by value: 
Create
Move
Destroy
Move
Destroy
Destroy
pass by value1: 
Create
Move
Destroy
Move
Destroy
Move
Destroy
Destroy
pass by reference: 
Create
Move
Destroy

值得注意的是,返回值调用在例程中仍然调用的是移动构造

Test ReturnRvalue1() {
    auto temp = Test();
    return temp;    //禁用RVO仍是调用移动构造
}

这是也是c++11引入的一个优化,但查了下他居然不叫返回值优化。

cpprefence

C++11 返回值优化、移动语义及函数返回值构造的重载决议_第1张图片
字面意思就是,某些自动存储周期(函数参数、函数体)的局部变量做返回值时,重载决议两次,先移动构造,再拷贝构造。

所以即使不考虑RVO 以下两种都是语法上都是合法的

std::unique_ptr<int> questionA(){
    auto t = make_unique<int>(99);
    return t;
}

std::unique_ptr<int> questionB(std::unique_ptr<int> t){
    return t;
}

你可能感兴趣的:(C\C++,杂谈,c++,开发语言)