C++ 中 move 语义的理解
2018-08-21 本文已影响79人
顽强的猫尾草
std::move
是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。
如 string
类在赋值或者拷贝构造函数中会声明 char*
数组来存放数据,然后原 string
中的 char*
数组被析构函数释放,如果 s
是一个临时变量,则上面的拷贝和析构就是多余的,完全可以把临时变量 s
中的数据直接 “转移” 到新的变量下面。
move 语义的场景中,往往都是一个临时对象传给了一个函数,C++11 语法规定:将一个右值(比如一个临时对象表达式)传给一个函数的时候,是优先绑定到参数形式是右值引用的函数上的。
【示例 1】s0 + " world."
这个表达式是个右值,因为它的结果是个临时对象,str
对象的构造函数在 C++11 之前调用的是传统的 Copy Ctor,而在 C++11 中会优先调用 Move Ctor。
std::string s0 = "hello";
std::string str = s0 + " world.";
看起来 move 和浅拷贝没有什么区别?但其实它还把源对象清空了。根据对象类别不同清空操作也不同,如果是指针就是置 nullptr
,如果是容器类就 clear
所有元素。所以如果原先的对象还想使用一定要注意需不需要重新初始化。
【示例 2】在将集合类型 newList 通过 move 语义传给 tmpList 后,newList 变为空集合,仍然可以使用:
std::set<string> newList;
// add IPs to newList
...
auto portStr = "9000";
auto tempList = std::move(newList);
for (auto & ipPort : tempList) {
auto index = ipPort.find(':');
if (std::string::npos == index) {
continue;
}
auto ip = ipPort.substr(0, index);
auto newIpPort = ip + ":" + portStr;
newList.insert(newIpPort);
}
其中,
npos
是一个常数,表示size_t
的最大值。许多容器都提供这个常数,用来表示不存在的位置。在string
类中,find()
方法在找不到指定值的情况下会返回string::npos
。
move 是和 copy 相对的:
- copy 就是照着别人的东西复制一份,所需的工作量随拷贝对象的不同而不同,比如拷贝一个字很快,拷贝一本书很慢。
- move 就是把别人书上的名字擦掉,写上自己的。因为 move 不需要复制,所以很快。其实就是把自己的指针指过去,把原属主的指针指向别处。