像调用普通方法一样调用构造函数和析构函数的注意事项和风险
Caveats and risks of calling a constructor and destructor like common methods?
在我的程序中有一个点,某个对象的状态需要重置为"出厂默认值"。该任务归结为完成析构函数和构造函数中写入的所有内容。我可以删除和重新创建对象,但是我可以像普通对象一样调用析构函数和构造函数吗?(特别是,我不想重新分配更新后的指针到新实例,因为它在程序的其他地方的副本中徘徊)。
MyClass {
public:
MyClass();
~MyClass();
...
}
void reinit(MyClass* instance)
{
instance->~MyClass();
instance->MyClass();
}
我可以这样做吗?如果是这样,有什么风险、注意事项、需要我记住的事情吗?
如果你的赋值操作符和构造函数写得正确,你应该能够实现它:
void reinit(MyClass* instance)
{
*instance = MyClass();
}
如果赋值操作符和构造函数写得不正确,修复它们。
将重新初始化实现为销毁后再构造的警告是,如果构造函数失败并抛出异常,对象将被销毁两次,而不会在第一次和第二次销毁之间再次构造(一次是通过手动销毁,一次是通过其所有者超出作用域时发生的自动销毁)。
可以使用place -new:
void reinit(MyClass* instance)
{
instance->~MyClass();
new(instance) MyClass();
}
所有指针仍然有效。
作为成员函数:
void MyClass::reinit()
{
~MyClass();
new(this) MyClass();
}
应该小心使用,参见http://www.gotw.ca/gotw/023.htm,它是关于使用此技巧实现赋值操作符的,但这里也适用一些要点:
- 构造函数不应该抛出
-
MyClass
不应该用作基类 - 它干扰了RAII,(但这可能是需要的)
感谢Fred Larson。
我可以这样做吗?如果是这样,有什么风险、注意事项、需要我记住的事情吗?
不,你不能这么做。此外,从技术上讲,析构函数调用是可能的,它将只是未定义的行为。
假设你已经正确地实现了类的赋值操作符,你可以这样写:
void reinit(MyClass* instance) {
*instance = MyClass();
}
您应该使用智能指针并依赖move语义来获得您想要的行为。
auto classObj = std::make_unique<MyClass>();
创建一个包装指针,为您处理动态内存。假设您准备将classObj
重置为出厂默认值,您所需要的是:
classObj = std::make_unique<MyClass>();
这个"移动赋值"操作将调用MyClass
的析构函数,然后将classObj
智能指针重新赋值到指向新构造的MyClass
实例。起泡,冲洗,必要时重复。换句话说,您不需要reinit
函数。然后,当classObj
被销毁时,它的内存将被清理。
instance->MyClass();
是非法的,你必须得到一个编译错误。
instance->~MyClass();
是可能的。这会做两件事之一:
- 没有,如果
MyClass
有一个简单的析构函数 - 运行析构函数中的代码并结束对象的生命周期,否则。
如果在对象生命周期结束后使用它,将导致未定义行为。
很少写instance->~MyClass();
,除非你首先用位置new创建对象,或者你打算用new位置重新创建对象。
如果你不知道,位置new创建一个对象时,你已经得到了存储分配。例如,这是合法的:
{
std::string s("hello");
s.~basic_string();
new(&s) std::string("goodbye");
std::cout << s << 'n';
}
您可以尝试使用位置new expression
new (&instance) MyClass()
- 什么时候调用析构函数
- C++-明确何时以及如何调用析构函数
- C++ 防止在映射中放置()时调用析构函数
- 调用析构函数以释放动态分配的内存
- C++:使用方法调用析构函数的顺序是什么?
- 向量推回调用析构函数时调用析构函数
- 如何在调用析构函数时优雅地停止/销毁带有阻塞调用C++线程?
- C++,我应该调用析构函数吗?
- 如何获取有关在 Clang LibTooling 中调用析构函数的信息?
- 当我从 std::vector 中的新放置调用析构函数时会发生什么?
- 为什么这里不调用析构函数
- 在调用 std::bind 的产品后意外调用析构函数
- 为什么在传递给函数而不是构造函数时调用析构函数?
- 如何在C++中调用析构函数
- 为什么为未删除的对象调用析构函数?
- 调用析构函数时出错
- C++ 在不释放内存的情况下调用析构函数
- 为什么在运算符删除中不调用析构函数?
- C++ 调用析构函数后动态模板队列"double free or corruption (out)"
- 在 postOrderDelete 上调用析构函数时引发的异常