以前弃用博客园的缘由是其不支持markdown语法。到今天偶然进来试了一下,发现Markdown toggle原来是能支持的(不知道是否是由于它升级了),遂从新启用。c++
在一年前学C++的时候就对引用,常引用和右值引用迷迷糊糊的,再加上老师实在是不给力啊!(当时我问她一个很基础的关于函数对象的问题,她问我,什么是函数对象)因此那时候就只知道使用惯例而不知其具体内涵。再加上近一年时间都在其余语言上花费精力,对它们的区别就更加模糊了。直到前几天在stackoverflow上问了个关于SFINAE的问题,才猛地感受到本身的C++彻底要回炉重练了。今天从新看回C++ Prime Plus,终于有了一种恍然大悟的感受了。程序员
既然引用参数/返回值的使用常出如今类的定义里,就以类为例:安全
class C { int data[1024]; } C foo(C c) { /* do sth */; return c; } const C& foo(C& c) { /* do sth */; return c; }
若是是以值来传递参数,返回值,那么一个函数的调用须要经历这几步:markdown
C a; C b = foo(a);
a => temp val (as arg) => arg c => temp val (as return value) => temp val (as arg in constructor) => bapp
咱们能够用c++语句来描述上述过程函数
a => tmpa = a => arg c => tmpc = c => tmpb = tmpc => bui
从a到tmpa的过程天然是为了保证值传递的语义,使得函数内对参数的修改不会影响到传入的变量自己,亦即不产生反作用。而从c到返回值tmpc的过程,当c是临时变量时,将发生”Named Return Value Optimization“。现代的编译器在返回以前将看到被返回的是一个临时变量且变量生命周期将随着离开函数而终结,所以编译器将变量转移到上层scope的临时对象中加以保存。编译器将根据变量提供的copy/move构造器决定这一过程是经过copy仍是move来完成。url
显然,从实参到形参的拷贝,和返回值时的拷贝过程是彻底能够避免的。方法就是将参数/返回值类型由值改成引用。这么一捋,引用类型参数所引用的对象,和返回值所引用的对象就很是清晰了。参数引用的对象天然是实参,而返回值的引用对象则是返回语句中返回的对象。也就是:spa
C& tmpa = a; // passing argument const C& tmpc = c; // returning result const C& tmpb = tmpc; // construct b
参数/返回值的传递就至关于上述语句。天然地,对于引用类型的限制的特性也一样做用于参数和返回值。好比:code
也就是说,不管如何,左值引用都没法引用表达式(由于表达式的结果是临时对象,即右值)。正是由于引用类型参数和本来的值类型参数在此行为上的差别。便产生了可以引用表达式的引用——右值引用。若是你但愿你的函数在接受参数时具备和接受值类型参数同样的行为,又想避免拷贝开销,就将参数类型声明为右值引用。
如今将临时对象传递给引用参数的问题解决了,那么返回值呢?如何返回一个临时变量,且避免拷贝开销?一个可选方案是,将接受返回结果的变量引用传递进函数内。事实上不少库函数就是采用这样的方法的。下面是一个简单的例子:
const int& add(const int& a, const int& b) { return a + b; } // warning: returning reference to local temporary object void add(const int& a, const int& b, int& r) { r = a + b; } // OK
当传入参数为右值引用时,在函数体内并不会被看做临时对象,这是出于安全的考虑。由于参数在函数内可能被引用屡次,而极可能其中一次的引用就“would be free to rip its guts out”掉了,这样的话接下来的对它的引用就都变成非法的了。正由于如此,程序员须要使用std::move
函数来明确指定在哪一个地方能够将它看做临时对象。好比在下面的例子里,在函数中,调用dosth
时传入的是a的副本,而在dosthelse
里则能够放心传入a自己了。
C foo(C&& a)
{
dosth(a);
dosthelse(std::move(a));
}
其实从clang在返回临时对象给引用的编译警告-Wreturn-stack-address
咱们就能大概看出左值和右值的区别所在了。右值和左值的根本区别就在于右值不能提供经过地址访问在任什么时候刻的有效性。天然也就没法被安全引用了。