C++ 当源obj被销毁时,使用move cstor是否会丢失内存?

C++ 当源obj被销毁时,使用move cstor是否会丢失内存?,c++,c++11,constructor,move-semantics,move-constructor,C++,C++11,Constructor,Move Semantics,Move Constructor,说我有课 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

说我有课

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
自身内为字段
某些对象分配内存。当移动发生时,我们交换指针,这样现在
a1
一些对象指向
a2
保存的内存块(而不是在其自身的内存空间上复制)。将来,当
a2
超出范围时,例如,包含
a2
的函数返回,因此堆栈帧将被清除,因为
a2。一些对象驻留在
a2
中,它也会被删除。由于
a1.一些对象在移动后指向
a2
现在已清理的内存,
a1
是否会丢失该部分信息


按照上述逻辑,
a1
现在将指向无效的内存空间

如果正确实现了move构造函数,则不会泄漏任何内存。特别是,一个典型的移动构造函数将rhs指针设置为
nullptr
,因此在moved from对象的析构函数中后续的
delete
是不可操作的。超级简化示例:

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
}

如果正确实现了move构造函数,则不会泄漏任何内存。特别是,一个典型的移动构造函数将rhs指针设置为
nullptr
,因此在moved from对象的析构函数中后续的
delete
是不可操作的。超级简化示例:

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
}

如果正确实现了move构造函数,则不会泄漏任何内存。特别是,一个典型的移动构造函数将rhs指针设置为
nullptr
,因此在moved from对象的析构函数中后续的
delete
是不可操作的。超级简化示例:

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
}

如果正确实现了move构造函数,则不会泄漏任何内存。特别是,一个典型的移动构造函数将rhs指针设置为
nullptr
,因此在moved from对象的析构函数中后续的
delete
是不可操作的。超级简化示例:

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
}

下面是一个移动类的典型实现

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;
};
模板
结构移动
{
移动()=默认值;
显式移动(大小\u t n)
:ptr(新T[n]){}
移动(移动常数&)=删除;
移动&运算符=(移动常量&)=删除;
移动(移动和维护)
:ptr(m.ptr){m.ptr=nullptr;}
移动和运算符=(移动和移动)
{if(this!=&m){delete ptr;ptr=m.ptr;m.ptr=nullptr;}返回*this;}
私人:
T*ptr=nullptr;
};
所以你可以自己弄清楚会发生什么


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

这里是移动类的典型实现

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;
};
模板
结构移动
{
移动()=默认值;
显式移动(大小\u t n)
:ptr(新T[n]){}
移动(移动常数&)=删除;
移动&运算符=(移动常量&)=删除;
移动(移动和维护)
:ptr(m.ptr){m.ptr=nullptr;}
移动和运算符=(移动和移动)
{if(this!=&m){delete ptr;ptr=m.ptr;m.ptr=nullptr;}返回*this;}
私人:
T*ptr=nullptr;
};
所以你可以自己弄清楚会发生什么


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

这里是移动类的典型实现

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;
};
模板
结构移动
{
移动()=默认值;
显式移动(大小\u t n)
:ptr(新T[n]){}
移动(移动常数&)=删除;
移动&运算符=(移动常量&)=删除;
移动(移动和维护)
:ptr(m.ptr){m.ptr=nullptr;}
移动和运算符=(移动和移动)
{if(this!=&m){delete ptr;ptr=m.ptr;m.ptr=nullptr;}返回*this;}
私人:
T*ptr=nullptr;
};
所以你可以自己弄清楚会发生什么


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

这里是移动类的典型实现

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;
};
模板
结构移动
{
移动()=默认值;
显式移动(大小\u t n)
:ptr(新T[n]){}
移动(移动常数&)=删除;
移动&运算符=(移动常量&)=删除;
移动(移动和维护)
:ptr(m.ptr){m.ptr=nullptr;}
移动和运算符=(移动和移动)
{if(this!=&m){delete ptr;ptr=m.ptr;m.ptr=nullptr;}返回*this;}
私人:
T*ptr=nullptr;
};
所以你可以自己弄清楚会发生什么


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

如果您实现或使用错误的移动构造函数,您所描述的情况就会发生。您的帖子中没有足够的信息来确定是否是这样。这次更新怎么样?move assign构造函数的代码似乎丢失了。我们不知道SomeObj
做了什么。我们甚至不知道你在说什么“字段指针”。你说,“我们交换指针”,但你的示例中没有指针。如果你实现或使用错误的移动构造函数,你所描述的将会发生。而且你的帖子中没有足够的信息来确定