我真的很困惑,我已经查了几次,它仍然没有点击。复制构造函数和移动构造函数在后台的内存使用情况如何?我真的不明白什么是“窃取资源”与移动构造函数。移动构造函数应该用于动态分配的内存还是堆栈上的内存?
我还被告知,如果我有这样的代码:
void someFunction(Obj obj){
//code
cout << &obj << endl;
}
int main(){
Obj o;
cout << &o << endl;
someFunction(o);
}
o
将被复制到obj
。我的印象是,复制在内存中创建一个新项,并将传递的数据复制到该对象的内存地址。因此obj
将在内存中创建一个新空间,o
的数据将复制到该空间。但是我得到的o
和obj
的地址完全相同,所以基本上我不知道发生了什么。
2条答案
按热度按时间c0vxltue1#
复制构造函数和移动构造函数在后台的内存使用情况如何?
如果调用了 any 构造函数,则意味着在内存中创建了一个新对象。因此,copy 构造函数和 move 构造函数之间的唯一区别是传递给构造函数的源对象是否将其成员字段 * 复制 * 或 * 移动 * 到新对象中。
我真的不明白什么是“窃取资源”与移动构造函数。
假设一个对象包含一个成员指针,指向内存中其他位置的一些数据。例如,
std::string
指向动态分配的字符数据。或者一个指向动态分配数组的std::vector
。或者一个std::unique_ptr
指向另一个对象。std::shared_ptr
)。另一方面,move 构造函数可以通过获取指向数据的指针的所有权来简单地“移动”数据,而将数据本身留在其所在的位置。新对象现在指向原始数据,源对象被修改为不再指向该数据。数据本身保持不变。
这就是为什么move semantics比 copy/value sematics 更高效。
下面是一个例子来说明这一点:
移动构造函数应该用于动态分配的内存还是堆栈上的内存?
移动语义 * 最常 * 用于指向动态资源的指针/句柄,是的(但也有其他情况下移动语义可能有用)。更新指向数据的指针比复制数据要快。知道源对象将不再需要引用其数据,不需要复制数据然后销毁原始数据,原始数据可以按原样从源对象“移动”到目标对象。
当被“移动”的数据是POD数据(普通的旧数据,即整数、浮点小数、布尔值、结构/数组聚合等)时,移动语义无助于提高效率。“移动”这样的数据与“复制”它是相同的。例如,您不能将一个
int
“移动”到另一个int
,您只能复制它的值。我还被告知,如果我有这样的代码:...
o
将被复制到obj
。在
someFunction(Obj obj)
的例子中,是的,因为它接受obj
参数 by value,从而调用Obj
的 copy 构造函数从o
创建obj
示例。在
someFunction(Obj &&obj)
或someFunction(const Obj &obj)
的例子中没有,因为它们采用obj
参数 by reference,因此根本没有创建新对象。引用只是现有对象的别名(在幕后,它被实现为对象的指针)。对引用应用&
address-of运算符将返回被引用对象的地址。这就是为什么在这些示例中,main()
和someFunction()
中打印了相同的地址。我的印象是,复制在内存中创建一个新项,并将传递的数据复制到该对象的内存地址。
基本上是的更准确地说,它将传递对象的成员字段的 * 值 * 复制到新对象的相应成员字段。
因此
obj
将在内存中创建一个新空间,o
的数据将复制到该空间。只有当
obj
是o
的 * 副本 * 时,才是。h43kikqp2#
雷米的回答很好,这里还有其他相关的问题。但如果答案对你来说仍然有些“抽象”,那么最好的方法就是自己看看到底发生了什么。考虑下面的类。
Myclass
必须是数据成员。一个整数和一个std::vector
如果你运行这个代码,你会得到如下的结果第一部分
这里我们只是打印原始对象。
第二部分
现在我们通过复制第一个对象来创建第二个对象。这将调用
Myclass
的复制构造函数。两个对象中的数据与预期相同,但它们是副本,因为内存地址在对象和``中不同。第三部分
我们创建了另一个对象,但现在我们将
obj1
移动到这个新对象。这将调用我们类的move构造函数。一旦一个对象从 * 移动,就像obj1
一样,我们不应该再使用它,除非我们给它赋值。现在,obj1.v
中的内部指针是一个空指针,请注意,obj3.v
存储自己数据的地址指向obj1.v
之前指向的地址。这就是将数据从一个对象移动到另一个对象的意思。但并不是所有的东西都能被移动。请注意,复制了整数
a
成员,而移动了向量v
成员。虽然int
的复制成本很低,但有时即使是复制成本不低的数据也无法移动。例如,如果我们将double arr[100]
数据添加到Myclass
,那么移动构造函数仍然会将obj1.arr
复制到新的obj3
对象,因为arr
在堆栈中。