为什么不能破坏一个对象然后用相同的名称再次实例化它

Why is not possible to destruct an object and then instantiate it again with the same name

我正在为其他人编写的代码创建单元测试,并且无法修改它们。

我正在尝试销毁一个对象,然后从头开始实例化它(所以构造函数将其置于初始状态)

这是我的代码:

state::State_Machine state_machine_test_off; 

//Check that OFF is initial state

EXPECT_EQ(States::OFF,state_machine_test_off.get_state());

//Change and check the behaviour from OFF to the other States

state_machine_test_off.change_state(States::LOADED);
EXPECT_EQ(States::LOADED,state_machine_test_off.get_state());
state_machine_test_off.~State_Machine(); //Destructor to iniciate again the process

state::State_Machine state_machine_test_off;
state_machine_test_off.change_state(States::INITIALISED);
EXPECT_NE(States::INITIALISED,state_machine_test_off.get_state());
state_machine_test_off.~State_Machine(); //Destructor to iniciate again the process

然后继续。我不想实例化一个新对象的原因是因为我有一个很大的状态矩阵,并且每个状态都可以通过 change_state() 移动到一些而不是其他人。

我在互联网上查看了有关析构函数的信息,我了解到可以显式调用它们,即使这不是一个很好的做法。

也许有人可以告诉我为什么当我析构然后再次实例化对象时编译器会失败?

PD: 析构函数是默认析构函数

state::State_Machine::~State_Machine() {}

您不能在调用析构函数之后在同一范围级别声明另一个具有相同名称的变量。析构函数不会从作用域中删除旧名称。

为了解决您的问题,我建议您只添加新级别的范围,因为看起来您在任何给定时间都只在几行中使用 state::State_Machine

{ state::State_Machine state_machine_test_off;
  state_machine_test_off.change_state(States::LOADED);
  EXPECT_EQ(States::LOADED,state_machine_test_off.get_state()); }

{  state::State_Machine state_machine_test_off;
   state_machine_test_off.change_state(States::INITIALISED);
   EXPECT_NE(States::INITIALISED,state_machine_test_off.get_state()); }

如果您仍想显式调用析构函数,则必须确保在同一个对象上多次调用析构函数是安全的(您说过您不能修改现有代码,所以要么这行得通,要么它不会)。在实践中,如果这很好用,我会感到惊讶,因为大多数析构函数都假设对象将被销毁,并且不会花时间将其标记为已销毁(这可能需要额外的状态,并且肯定需要循环) .

如果你仍然坚定,尽管复杂和风险,你可以这样写:

state_machine_test_off.~State_Machine(); //Destructor to iniciate again the process

new (&state_machine_test_off) state::State_Machine;

这利用了放置 new,如果您正确使用范围(见上文),这是完全没有必要的。您还必须考虑如果构造函数失败会发生什么情况,特别是因为您仍然 需要处理已经被销毁的对象,再次调用它的析构函数。

问题是您正在重新定义您已经定义的变量。当你做

state::State_Machine state_machine_test_off; 

您基本上将范围内的名称 state_machine_test_off 锁定为该变量。您稍后无法执行 state::State_Machine state_machine_test_off; 重置它,因为它会尝试定义一个新变量并且名称 state_machine_test_off 已被占用。

要在销毁对象后重建对象,您需要使用 placement new 让它再次调用该对象的构造函数。那看起来像

new (&state_machine_test_off) state::State_Machine();

现在 state_machine_test_off 的存储中有一个新的默认构造 state::State_Machine


也就是说,如果您只是将对象重新分配给默认构造值,如

,那么所有这些手动调用和未定义行为的可能性都会消失
state_machine_test_off = state::State_Machine{};