1.问题引出
最近在新的环境上编译以前使用过boost的c++程序,发现对boost的相关调用部分报错了,而且报错发生在boost的内部的hpp文件中
报错内容:cannot bind rvalue reference of type to lvalue of type
通过实际查看boost报错部分的代码,发现报错部分的代码类似于这样:
main.cpp:
#include <stdio.h>
template<typename T>
void f1(const T&& a)
{
printf("f1:%d\n",a);
}
void f2(const int & e)
{
f1<const int>(e);
}
int main()
{
int a = 10;
f2(a);
return 0;
}
编译:g++ main.cpp -o main
编译报错,提示:
error: cannot bind rvalue reference of type 'const int &&' to lvalue of type 'const int'
在这一行:f1<const int>(e)
报错与boost中一致
2.右值引用
编译提到了右值引用(rvalue reference),说明默认使用了g++11新特性,在g++11的新特性里面,加入了右值引用
右值引用:即(Move Semantics:移动语义),避免无意义的拷贝赋值操作,C++11提出右值引用的概念,其本质是接替右值的所有权(不销毁原先的内存内容,而是将所有权移交给被交付的对象。)。
int &&value = 1 ;//右值引用一个常量值
int &&value = fun();//右值引用一个临时的函数返回值
相对于左值,右值的生命周期很短,如函数的临时返回值,可以安全的转移控制权。
将右值的资源不释放,而是采取右值引用的方式继续使用,减少大量的拷贝,复制带来的开销。
编译器会默认开启返回值优化,解决重复对象构造问题,而采取右值引用可以语言层面实现。
子中的问题出在,右值引用专门是用来引用右值的,不可以引用左值,而f2函数中的e,是个左值引用,其不可以传给右值引用,
类似于:
int a = 2;
int &&b = 3;//可以,右值引用的就是3
int &&c = a;//不可以,右值引用不能引用左值,而a是个左值
3.解决方式
要解决boost的这个编译报错,不想禁用g++的c++11功能,又不能改变boost中的那部分报错代码,因为按照对boost的调用情况,确实会走到报错代码的地方,那是什么原因会让上层传下来的参数最后变成了编译会出错的右值引用呢?在boost的config.hpp中,会有一些列检查当前机器环境的宏,由于机器环境的不同,某些宏会被意外打开或是关闭,导致出现了宏分支。通过查看config.hpp中的宏开关,发现在当前程序中,通过定义BOOST_ASIO_DISABLE_MOVE宏,就可以关掉config.hpp中的宏走向,这样禁止了意外使用右值引用的情况。