C++11特性学习std::move和std::forward

参考文章:
左值引用、右值引用、移动语义、完美转发,你知道的不知道的都在这里
[C++特性]对std::move和std::forward的理解

1. std::move

最近在学习C++11特性,然后关于std::move()的一些理解和疑问先记录一下。
欢迎大神在评论区指正!

1.1 需求

  • 目的是为了提高性能,减少拷贝次数

1.2 使用场景

  • std::shared_ptr引用使用场景有什么区别?
    – 这两者传入函数都不会引起对象内存的拷贝,可以在函数内访问对象
    std::move配合移动构造函数使用,在使用对象A创建对象B的时候,把对象A的数据权限移交给B,这样子对象B就不用再去拷贝。所以使用std::move要求对象实现了构造函数,否则没有优化效果
    STL的类型实现了移动构造函数,可以放心使用,如果自己写的类要想实现使用std::move达到性能优化的效果,也要实现移动构造函数

1.3 右值和右值引用

  • 右值按照概念的就是不能通过地址访问的数据,需要注意的一点就是字符字面量"abcd"是左值
  • 右值引用类型使用符号&&表示,std::move的作用就是把左值转换为右值引用类型
    &是左值应用类型?
    – 左值和右值只是属性区分?
  • 个人理解
    假设存在类A,类A实现了拷贝构造移动构造
    因为拷贝构造是C++11之前就实现了,现在想实现移动构造函数,要实现构造函数重载需要参数列表不同,参数列表不同的话可以是个数,类型,或者参数顺序,构造函数只能传入一个参数,所以只能是参数类型不同,为了实现移动构造函数的调用,从而加入了右值引用类型
A a(A()); //调用拷贝构造
A b(std::move(A())); //调用移动拷贝构造

1.4 返回值是临时对象,需要使用std::move

编译器有优化,会使用移动构造函数。
所以在其他场景需要显示调用std::move来决定使用拷贝构造还是移动构造,因为编译器不清楚你接下来是否需要继续使用对象,还是对于对于使用将亡值进行初始化,都是调用移动构造函数?

2 std::forward

2.1 需求

解决引用折叠导致右值引用被隐式转换为左值引用的场景.

  • 这里有点晦涩。然后不太懂
class A;
void test(A && a)
{
	A tmp = a; //隐式转换???调用的是拷贝构造
}
void main()
{
	A a;
	test(std::move(a));
}
引用折叠

T& & -> T& (对左值引用的左值引用是左值引用)
T& && -> T& (对左值引用的右值引用是左值引用)
T&& & ->T& (对右值引用的左值引用是左值引用)
T&& && ->T&& (对右值引用的右值引用是右值引用

2.2 疑问

  • 和std::move搭配使用还是一个取代作用?
    • 搭配使用

实例代码

#include 

using namespace std;

class A
{
public:
    A() {}
    A(const A&){printf("copy\n");}
    A(const A&&){printf("move\n");}
};


void test(A&& a)
{
    A tmp = a; //copy. 没使用std::forward进行二次转发的时候,实际上是会被隐式的转换,转发成一个左值引用,从而调用不符合期待的构造函数
    A xxx = std::forward(a);//move
}

//使用模本也是一样的
template
void improve(T&& a)
{
    T tmp = a; //copy
    T xxx = std::forward(a); //move
}

int main() {
    A a;
    test(std::move(a));
    improve(std::move(a)); //注意:一般move将亡值,这里再move一次是因为A的移动构造没有实现。再次move会导致没有资源可以转移
    return 0;
}

你可能感兴趣的:(学习总结,c++,学习,开发语言)