c++对象所有权的手记-创新互联

1.先理解下c++为什么会需要move?

---- 变量,所有权,以及性能优化。

我们提供的服务有:成都网站制作、成都做网站、微信公众号开发、网站优化、网站认证、青铜峡ssl等。为上1000家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的青铜峡网站制作公司2.变量

从实用的角度,变量可以分为两类:

  1. 没有指针或引用的变量,可以称为trivial type。  (c++11,平凡可复制的概念用的也是trivial这个词)
  2. 有指针或引用的变量,可以称handle type。

简化理解,trivial type数据,没有指针、引用直接放在栈上的,无须优化性能。

而handle type通常有两部分数据:第一部分可以放在栈上,第二部分在堆里

栈上的数据——就叫做handle,用来控制(handle)堆上的数据。从这个角度看栈上的数据是堆数据的所有者(owner) )。

c++ 语法move一般针对的是handle type的变量。

为什么Python,JavaScript,Java等等都没有move这个概念呢?

因为在这些有GC的语言里面,它们处理handle type的时候,赋值既具有"move"的性质,又具有copy的性质——实际是将引用复制给另外一个变量。

比如下面JavaScript代码

let a = { name: "good"};
let b = a;
b.name = "Bad";
// a,b的名字都变成了bad.

这里变量b与a引用着同样的对象,它们就是一个引用而已。

b = a就是将这个名字给了b变量,它们指代的是同一个东西。

当我们通过b修改数据,此时a引用着的对象自然而然就已经修改了。

显然,此时无所谓move动作,因为b跟a指代同样的对象,这是很直观的想法。

更准确的说法是copy 栈上的名字,根本没有发生任何所有权的转移概念。

我们看下 C++里面,类似的b = a,默认的是拷贝复制,而不是引用。

void test()
{
	auto a = vector{ "str1", "str2", "str3" };
		auto b = a;
		b[0] = "b string";
		for (auto v : a) {
			cout<< v<< ", ";
		}
		cout<< endl;
		for (auto v : b) {
			cout<< v<< ", ";
		}
		cout<< endl;
}

输出:

str1, str2, str3,
b string, str2, str3,

对比js的引用a、b,都在栈上,天然的指向同一个堆空间,只是别名。

而c++的变量a、b,都在栈上,指向了不同的堆空间,b=a,是复制了一份给到b指向的空间。

(像java,JS等有GC的语言为了更好地管理内存,基本不做堆栈的区分——不用关心是在栈上还是堆里。GC帮忙管理着内存,这是这些语言没有move概念的原因)

上面JS例子只拷贝了栈上面的引用(它们无须操作堆复制),而C++既拷贝了栈那部分数据也拷贝了堆里面的内容

如果,c++想实现所有权的转换呢,因此,C++11 引入了move的概念,我们只拷贝栈上的数据的时候,并引用到已有的堆数据(不另外分配堆内存并拷贝堆数据,提高性能)。

3.value categories也做了调整,从而规定哪些value可以被move

(左值、右值、将亡值)

  1. prvalue - 纯右值 。就是用于计算的或者用于初始化对象的。(pure)
  2. xvalue -  将亡值。就是临时变量。它是快要被销毁的值。(expiring)
  3. lvalue -  左值。在内存中具有位置的值。所有具名变量都是左值 (left)

xvalue可以被直接move。

prvalue被move的时候,可以理解生成了一个临时变量xvalue,并move了这个临时变量。

lvalue,则需要使用std::move将lvalue变成xvalue,并move了这个xvalue。

4.c++中的move

     std::string a = "stringaaa";
     auto b = std::move(a);
     cout<< b<< endl;
原来变量a指代的值的所有权转移给了b,变量a被置成“空”了

move的场景例子。

  1. 接管资源
void My::take(Book && iBook) 
{
  mBook = std::move(iBook); //将没人要的iBook,拿过来据为己有
}

2. 转移所有权

auto thread = std::thread([]{});
std::vectorlThreadPool;
lThreadPool.push_back(std::move(thread)); //现在thread pool来掌控着thread

3. 避免拷贝

void f() {
  std::vector v = ...;
  take(std::move(v)); // 直接move进了函数g里面,不用拷贝
}

move是转移对象的所有权,所以我们可以move的是可以转移所有权的对象。

可以移动右值,也可以把左值通过std::move变成右值,从而可以实现移动。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网页标题:c++对象所有权的手记-创新互联
分享路径:http://hbruida.cn/article/didese.html