c++ 右值引用 左值引用
下面代码 看出右值引用 跟左值引用的相似之处,都具有别名的左右,可以与它引用的变量共同修改地址内的内容
左值/右值引用可以延长临时变量的寿命,直到该右值引用的寿命结束才析构
右值引用可以直接引用临时变量(如常量 1 ,3.1等),且可以对它进行修改(不指定const)
左值引用一般不会用于引用临时变量,虽然通过一些手段可以编译成功,但不安全也没有意义
struct RefTest{
RefTest()
{
str = "constructor";
}
~RefTest()
{
str = "destructor";
std::cout<<str.c_str()<<" ~RefTest"<<std::endl;
}
std::string&& getrvalue_ref() &&
{
return std::move(str);
}
std::string& getlvalue_ref()
{
return (str);
}
std::string str;
};
void test1()
{
RefTest a;
RefTest&& b = std::move(a);
std::cout<<a.str.c_str()<<"\t"<<b.str.c_str()<<std::endl;
a.str = "change";
std::cout<<a.str.c_str()<<"\t"<<b.str.c_str()<<std::endl;
//constructor constructor
// change change
// int& c = 3; //不能编译通过,右边是右值
int&& c = 3;
c++;
std::cout<<c<<"\t"<<std::endl;
//4
RefTest(); //立即析构
// destructor ~RefTest
RefTest&& d = RefTest(); //函数结束后析构
d.str = "change";
std::cout<<d.str.c_str()<<std::endl;
// change
std::string&& e = RefTest().getrvalue_ref();
std::cout<<e.c_str()<<"\t"<<std::endl;
e = "change";
std::cout<<e.c_str()<<"\t"<<std::endl;
// destructor ~RefTest
// destructor
// change
std::string& f = RefTest().getlvalue_ref();
std::cout<<f.c_str()<<"\t"<<std::endl;
f = "change";
std::cout<<f.c_str()<<"\t"<<std::endl;
// destructor ~RefTest
// destructor
// change
// destructor ~RefTest
// destructor ~RefTest
}
对于函数的返回值如果是临时变量(函数内建的变量,既不是参数变量也不是类成员变量),不能返回引用!
对c++ 在编译的时候会对返回值进行优化,如果返回的是临时变量(注意不是引用!),则会直接使用该临时变量的地址,不会进行内容的迁移和内参的释放,因此效率比较高。这也说明返回值处一般不需要使用move来强制转换右值,多此一举。
int getrvalue()
{
return 2;
}
int& getlvalue_ref()
{
int a = 3;
return a;
}
struct Rvaluetest
{
Rvaluetest(int i):str(new char[15])
{
value = i;
str[0] = 'c';
str[1] = 0;
cstr = "test";
}
~Rvaluetest()
{
value = 0;
std::cout<<" ~Rvaluetest "<<cstr.c_str()<<std::endl;
delete str;
}
int value = 2;
char * const str;
std::string cstr;
};
Rvaluetest&& getrvalue_ref()
{
Rvaluetest a(5);
return std::move(a);
}
Rvaluetest getrvalue_test()
{
Rvaluetest a(5);
return (a);
}
void RefTest()
{
// int& c = getrvalue(); //error invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
const int& c = getrvalue();
std::cout<<c<<"\t"<<std::endl;
// 2
int&& d = getrvalue();
d++;
std::cout<<d<<"\t"<<std::endl;
// 3
int& e = getlvalue_ref(); //编译能通过 但 再次调用该变量会出现 Segmentation fault
// std::cout<<e<<"\t"<<std::endl; //Segmentation fault
Rvaluetest&& f = getrvalue_ref();
std::cout<<++f.value<<"\t"<<f.str<<" "<<f.cstr.c_str()<<std::endl;
//乱码,说明运行了析构函数,因此虽然能够编译通,并能够运行,但是不安全
//右值引用终究还是引用,他并没有对内存的释放权,如果它引用的内存寿命短暂,可能会出错
// ~Rvaluetest test
// 1 �$���
Rvaluetest g = getrvalue_test(); //因为c++ 编译器的优化,该函数内建的临时变量并没有运行析构函数,而是整体通过返回值返回转移到g,寿命延长
//函数的返回值是右值,这也说明,c++中右值的赋值是直接地址赋值,并没有内容的迁移和内参释放,高效
std::cout<<++g.value<<"\t"<<g.str<<" "<<g.cstr.c_str()<<std::endl;
// 6 c test
// ~Rvaluetest test
}