bosthhe1 / cpushpush

0 stars 0 forks source link

右值引用的移动语义/完美转发 #41

Open bosthhe1 opened 1 year ago

bosthhe1 commented 1 year ago

移动语义包括移动复制和移动构造,都是为了解决传值的深拷贝问题,存在移动复制或者移动构造,代价就比深拷贝小很多,仅仅为资源交换 但是存在有一点我是不能理解,右值引用之后,相当于将右值开了个空间保存起来,不也是一个深拷贝吗,也可以是只用深拷贝一次。

bosthhe1 commented 1 year ago

移动构造:移动构造是用一个临时对象初始化对象,这个临时对象不能是匿名对象,可以是隐士类型转换的对象 如:string st = to_string(1111);这里构造一个局部变量s1,s1出了作用域会销毁,所以不能引用返回,s1就会拷贝构造一个临时变量tmp,然后使用临时变量去构造string,如果没有编译器优化和移动复制,那么这里会产生一次构造,两次拷贝构造 image 编译器优化后,在函数出作用域前,就直接拷贝构造给st,就直接是一次构造,一次拷贝构造,优化了tmp这一次 image 如果写了移动构造加编译器不优化 image 编译器优化 image

bosthhe1 commented 1 year ago

移动复制和移动构造原理一样会进行优化 以string st;st = to_string(1111);不写移动赋值:一次拷贝构造+一次赋值 image 编译器优化,在s1销毁前,赋值给st image 写移动赋值编译器不优化 image 编译器优化 image

bosthhe1 commented 1 year ago

在移动构造中,因为移动构造是将常量用一块内存保存起来,所以移动构造之后的变量,是可以取地址的,这样移动构造后的值的意义就变了,为了保持原来的语义std加入了forward

void func2(int&& a)
{
    cout << "func2()"<<&a << endl;//对a取地址
}
void func1(int&& a)
{
    cout << "func1()" <<&a << endl;//对a取地址
    func2(forward<int>(a));//这里注意forward的书写格式
}
int main()
{
    func1(1);
    return 0;
}

image 我们看到这个移动构造的a都是同一个a,所以不存在移动构造嵌套会开多个空间

bosthhe1 commented 1 year ago

在模板中出现&&,这种情况,这里的&&是为万能引用,既能引用左值,也能引用右值,但是引用之后的值都将退化为左值,所以需要完美转发forward(),来保障传参过程中的参数性质不变 image