当源obj被销毁时,使用move-cst是否会丢失内存

Does using move cstor lose memory when the source obj is destroyed?

本文关键字:是否 move-cst 内存 使用 obj 当源      更新时间:2023-10-16

假设我有一个类

MyClass {
  //.. cstors and dstor
  void MyClass(MyClass&& source) : some_obj_(std::move(source.some_obj_));
  SomeObj some_obj_;
}

假设我执行以下操作:

// a1 is defined somewhere else with a wider scope
MyClass a1; 
...
// a2 is defined locally and will go out of scope soon
MyClass a2; 
... //Populate a2's some_obj_ field with data
a1 = std::move(a2); // move instead of copy

在这种情况下,将调用move构造函数。据我所知,move构造函数在两者之间交换字段指针,这样就不会发生复制。

所以我的问题来了。当a2被实例化时,它在a2自身内为字段some_obj_分配内存。当移动发生时,我们交换指针,使a1some_obj_现在指向a2所持有的内存块(而不是在其自己的内存空间上复制它)。将来,当a2超出范围时,例如,包含a2的函数返回,因此堆栈帧被清理,因为a2.some_obj_位于a2中,所以它也被删除。既然a1.some_obj_在移动后指向了a2现在已经清理过的内存,那么a1会丢失那部分信息吗?

似乎按照上面的逻辑,a1现在将指向无效的内存空间。

以下是移动类的典型实现

template<typename T>
struct moving
{
  moving()=default;
  explicit moving(size_t n)
  : ptr(new T[n]) {}
  moving(moving const&)=delete;
  moving&operator=(moving const&)=delete;
  moving(moving&&m)
  : ptr(m.ptr) { m.ptr=nullptr; }
  moving&operator=(moving&&m)
  { if(this!=&m) { delete ptr; ptr=m.ptr; m.ptr=nullptr; } return*this; }
private:
  T*ptr=nullptr;
};

所以你可以自己想清楚会发生什么。

请注意,移动语义仅与管理外部资源的情况相关(例如,保存已分配内存地址的指针或指向某种类型的库管理资源(如HDF5 id)的句柄)。对于其他普通数据,移动与复制没有什么不同。

如果move构造函数实现得当,就不会泄漏任何内存。特别是,典型的move构造函数将rhs指针设置为nullptr,因此moved-from对象的析构函数中的后续delete是no-op。超级简化示例:

X::X(X&& rhs)
{
    this->p = rhs.p; // here p is a pointer
    rhs.p = nullptr; // now the delete p from the dtor of rhs is a no-op
}