我的程序中有一点需要重置某个对象的状态"出厂默认值"。任务归结为执行在析构函数和构造函数中编写的所有内容。我可以删除并重新创建对象 - 但是我可以将析构函数和构造函数作为普通对象调用吗? (特别是,我不想将更新的指针重新分发到新实例,因为它在程序的其他位置存在副本)。
MyClass {
public:
MyClass();
~MyClass();
...
}
void reinit(MyClass* instance)
{
instance->~MyClass();
instance->MyClass();
}
我可以这样做吗?如果是这样,是否有任何风险,警告,我需要记住的事情?
答案 0 :(得分:3)
如果正确编写了赋值运算符和构造函数,则应该能够将其实现为:
void reinit(MyClass* instance)
{
*instance = MyClass();
}
如果您的赋值运算符和构造函数编写不正确,请修复它们。
实现重新初始化作为破坏后跟构造的警告是,如果构造函数失败并抛出异常,对象将被破坏两次而不会在第一次和第二次破坏之间再次构建(一次是通过手动破坏,并且一旦它的所有者超出范围就会发生自动销毁)。这有不明确的行为。
答案 1 :(得分:2)
您可以使用placement-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
不应用作基类答案 2 :(得分:1)
我可以这样做吗?如果是这样,是否有任何风险,警告,我需要记住的事情?
不,你不能这样做。除了它在技术上可能用于析构函数调用之外,它只是未定义的行为。
假设您已经实现了类correctly的赋值运算符,您可以写:
void reinit(MyClass* instance) {
*instance = MyClass();
}
答案 3 :(得分:1)
你应该使用智能指针并依靠移动语义来获得你想要的行为。
auto classObj = std::make_unique<MyClass>();
这会创建一个包装指针,为您处理动态内存。假设您已准备好将classObj
重置为出厂默认值,您只需:
classObj = std::make_unique<MyClass>();
这&#34;移动任务&#34;操作将调用MyClass
的析构函数,然后重新分配classObj
智能指针以指向新构造的MyClass
实例。泡沫,冲洗,必要时重复。换句话说,您不需要reinit
功能。然后,当classObj
被销毁时,其内存将被清除。
答案 4 :(得分:1)
instance->MyClass();
是非法的,您必须收到编译错误。
instance->~MyClass();
是可能的。这可以做两件事之一:
MyClass
有一个简单的析构函数如果在生命周期结束后使用对象,则会导致未定义的行为。
除非您首先使用 placement new 创建对象,否则编写instance->~MyClass();
的情况很少见,或者您即将使用展示位置重新创建对象。
如果您不知道, placement new 会在您已分配存储空间时创建对象。例如,这是合法的:
{
std::string s("hello");
s.~basic_string();
new(&s) std::string("goodbye");
std::cout << s << '\n';
}
答案 5 :(得分:0)
您可以尝试使用placement new表达式
new (&instance) MyClass()