在这段代码中,Apple和Fruit的析构函数根本没有被调用。我在两者中都有std::cerr
个语句,并且Apple中的一些清理代码无法运行。我认为调用删除就足够了?我正确地做RAII吗?我还用std :: unique_ptr替换了原始指针,结果相同。
int32_t Fruit::frutificate(const Settings& settings) {
Fruit *listener;
if (settings.has_domain_socket()) {
listener = new Apple(settings);
} else {
listener = new Orange(settings);
}
int r = uv_run(listener->loop, UV_RUN_DEFAULT);
delete listener;
return r;
}
更新 所有类都有虚拟析构函数。
答案 0 :(得分:6)
首先,您的直接问题几乎肯定是~Fruit()
不是virtual
。将其(virtual ~Fruit() = default
或virtual ~Fruit() {}
添加到class Fruit
),您的代码(已发布)将神奇地开始工作。
然而,这不是您的代码应该是什么。工作,嗯,不够好。
您可以对代码进行一些改进。作为第一个改进,我们将使用unique_ptr
:(作为评论中提到的@Deduplicator)
int32_t Fruit::frutificate(const Settings& settings) {
std::unique_ptr<Fruit> listener;
if (settings.has_domain_socket()) {
listener.reset( new Apple(settings) );
} else {
listener.reset( new Orange(settings) );
}
int r = uv_run(listener->loop, UV_RUN_DEFAULT);
return r;
}
使用RAII来确保监听器的生命周期。好多了,不再需要手动delete
(可能偶然错过或例外)。
在C ++ 14中,.reset(new Blah(whatever))
可以替换为= std::make_unique<Blah>(whatever);
,现在您的代码从未明确调用new
和delete
,这是一个好习惯进入。但是你的代码被标记为C ++ 11,所以我将把C ++ 11版本保留在上面。
虽然这样做更好,但我们可以做得最好。根本不需要使用免费商店(堆)。
避免免费使用商店的一种简单方法是:(在上面的评论中从@Jarod偷来)
int32_t Fruit::frutificate(const Settings& settings) {
if (settings.has_domain_socket()) {
return uv_run(Apple(settings).loop, UV_RUN_DEFAULT);
} else {
return uv_run(Orange(settings).loop, UV_RUN_DEFAULT);
}
}
具有重复uv_run
代码的缺点(因此可以滋生错误)。我们可以用lambda来解决这个问题:
int32_t Fruit::frutificate(const Settings& settings) {
auto fruit_the_uv = [&](Fruit&& fruit) {
return uv_run(fruit.loop, UV_RUN_DEFAULT);
};
if (settings.has_domain_socket()) {
return fruit_the_uv( Apple(settings) );
} else {
return fruit_the_uv( Orange(settings) );
}
}
我们将公共代码分解为lambda,然后在两个分支上调用它。当我们传递临时果实时,我使用了右值参考。