首页
随机
最近更改
特殊页面
社群首页
参数设置
关于WHY42
免责声明
WHY42
搜索
用户菜单
登录
欢迎来到Riguz的小站!这是一个私人wiki,用来记录一些我的笔记。
查看“︁C++ NRVO”︁的源代码
←
C++ NRVO
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
对于C++这种需要精细管理对象的语言来说有时候真是比较复杂,一个看似简单的问题一直在困惑着我:到底可不可以在方法中返回局部变量呢? = 可以返回临时变量= 答案是肯定的,如果我们在一个方法中返回了临时变量,这个临时变量实际上是在栈里面的,当执行完方法后栈就销毁了,那么为什么我们还可以这样做呢?来看一个例子: <syntaxhighlight lang="c++"> #include <iostream> using namespace std; class Value { public: Value(int _m):m(_m) { std::cout << "test constructor" << m << std::endl; } Value(const Value& t) { std::cout << "test copy constructor" << m << std::endl; this->m = t.m; } ~Value() { std::cout << "test destructor" << m << std::endl; } void print() { std::cout << "m:" << m << std::endl; } private: int m; }; class Producer { public: Value produce(int i) { Value t(i); return t; } }; int main(int argc, char* argv[]) { std::cout << "Hello world!" << std::endl; Producer p; Value t = p.produce(100); t.print(); return 1; } </syntaxhighlight> 执行的结果是: <pre> Hello world! test constructor100 m:100 test destructor100 </pre> 结果证明这样做其实是可以取到我们定义的值的,这么做可行的原因是,实际上,编译器会帮我们把临时变量拷贝一份出来,所以即便栈销毁了,我们也能够拿到新的值。 = 不要返回临时变量的引用= 那么,如果我们返回临时变量的引用呢? <syntaxhighlight lang="c++"> class Producer { public: Value* produce(int i){ Value t(i); return &t; } }; </syntaxhighlight> 这样做得到的结果是不对的: <pre> test.cpp:21:17: warning: address of stack memory associated with local variable 't' returned [-Wreturn-stack-address] return &t; ^ 1 warning generated. Hello world! test constructor100 test destructor100 m:-327065280 </pre> 编译器会有一个警告,尽管我们仍旧可以运行我们的代码,但是实际上我们得到的值是不对的。 = NRVO机制= 那么,既然我们返回临时对象的值,实际上会得到一个拷贝的对象,那么如果我们有拷贝构造函数,是不是应该被调用呢? 然而在前面的例子中,拷贝构造函数并没有被调用到,这又是为什么呢?答案就是因为NRVO(Return Value Optimization)。这是c++11中的特性。我们首先可以尝试禁用掉这个特性,看看会发生什么。 <pre> hfli@CNhfli ~ $ g++ -fno-elide-constructors test.cpp hfli@CNhfli ~ $ ./a.out Hello world! test constructor100 test copy constructor0 test destructor100 test copy constructor0 test destructor100 m:100 test destructor100 </pre> 可以看出,拷贝构造函数调用了两次,第一次是在produce函数中返回的时候,第二次是我们在给变量赋值的时候。
返回
C++ NRVO
。