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
做了什么。我们甚至不知道你在说什么“字段指针”。你说,“我们交换指针”,但你的示例中没有指针。如果你实现或使用错误的移动构造函数,你所描述的将会发生。而且你的帖子中没有足够的信息来确定