我已阅读帖子:Why do we need to set rvalue reference to null in move constructor?
它说在移动过程中,你只是将指针从一个对象复制到另一个对象,所以两个指针指向临时对象。当临时对象超出范围时,它的析构函数将运行。然后由2个指针指向的对象将是deallocates。因此,移动构造函数构造的对象的指针字段将指向不可用的位置。
但是,请查看以下代码:
int *p = new int(3);
int *q = p;
delete p;
std::cout << *q << std::endl;
删除指针p
后,指针q
仍然可以访问int
对象。
那么,这只是因为当rvalue引用访问对象时会产生差异吗?
答案 0 :(得分:2)
不,你不能。它似乎有效,但它完全是未定义的行为。内存将释放到运行时。
当您移动某些内容时,您有效地说原始对象不再有效 - 您只能从移动到的对象访问其原始内容。此外,移动后设置为NULL可防止双重删除 - 当原始对象超出范围并尝试释放该内存时,它将立即失败(如果新对象已经空闲&#39; d)或当新对象本身试图释放该内存时,它将失败。
答案 1 :(得分:1)
Accessing delete
d memory of the free store is undefined behavior.
在移动构造中,构造对象的指针设置为右值的指针,然后将其设置为nullptr
。
rvalue 引用的对象在此之后终止其生命周期,毕竟它是临时。因此,设置为nullptr
的指针预计不会再使用。当它被破坏时,执行delete nullptr;
,即无操作
OTOH,当构造对象的生命周期结束时,实际资源为deleted
- 指向它的指针在移动构造函数中指定。
答案 2 :(得分:0)
不,删除指针p后,指针q 无法仍然访问int对象。如果你不这么认为,因为你运行它并在输出中得到3 - 这是因为你造成了未定义的行为而UB可以&#34;工作&#34;作为众多选择之一。
一般情况下,内存地址尚未被重用,仍然属于程序(因此它有权访问且值尚未被删除),所以你会看到任何内容值已在该内存中删除。所有这一切都意味着,如果代码完全没问题就会显得好像。在这种情况下你也可以使用* p进行打印,它也没有什么不同。 p和q变量都包含相同的地址......由删除释放。
其中一个有趣的方面是高安全性应用程序或GPG等加密应用程序用垃圾手动填充已删除的内存,这样它就不会被嗅出 - 让私钥可以访问世界。否则,密钥仍然只能写入RAM,直到有人在那里写了其他东西!
答案 3 :(得分:0)
您链接的问题和您的问题都是在取消引用q
时试图避免未定义的行为。
问题是,(在链接的问题中)您必须知道,通过将其设置为q
,您不能再取消引用nullptr
(您没有管理它)。但是,在q
之后,不要取消引用delete
是您的事。在q
之前删除std::cout << *q << std::endl;
是非常可预测的。你取消引用它是你的错!
尽管如此,将q
设置为nullptr
有助于调试,delete q
不再是UB,nullptr
表示指向不存在的对象的指针。
答案 4 :(得分:0)
这是指针的问题。它们不传达所有权语义。
您应该使用std::unique_ptr
之类的内容。当您将指针从一个对象移动到另一个对象时,旧对象会识别它不再拥有该对象,因此您可以访问该数据。
简单的解决方案。就像其他C ++社区一样,停止使用这样的指针。
std::unqieu_ptr<int> p(new int(3));
std::unique_ptr<int> q = p; // Fails to compile
std::unqieu_ptr<int> p(new int(3));
std::unique_ptr<int> q = std::move(p); // explicitly transfer ownership.
// delete p; // No longer need this as when the onbject goes out of scope
// it is deleted.