在C ++中,当出现问题时,通常认为在构造函数中抛出异常是一种很好的策略。
但是,当失败的对象不是堆栈变量时,我对清理为失败对象分配的实际内存感到困惑。
考虑:
class Foo
{
public:
Foo()
{
throw std::runtime_error("Fail!");
}
};
int main()
{
Foo* f;
f = new Foo();
}
如果我使用valgrind --leak-check=full
运行此程序,则会报告:
=24981== 34 bytes in 1 blocks are possibly lost in loss record 2 of 3
==24981== at 0x4C286E7: operator new(unsigned long) (vg_replace_malloc.c:287)
==24981== by 0x4EEE998: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==24981== by 0x4EF0384: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==24981== by 0x4EF0462: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==24981== by 0x400D14: Foo::Foo()
...这向我表明,为Foo
实例分配的内存从未被回收。当然,这是有道理的,因为在C ++中,new
运算符实际上正在做两个事物。首先,它分配一个原始内存块(类似于malloc
),然后通过调用构造函数Foo::Foo()
来初始化原始内存。但由于Foo::Foo()
抛出异常,所以分配的初始原始内存永远不会被回收。
那么,我该如何收回它?我无法捕获异常和delete
对象,因为在抛出异常时我甚至没有指向对象的指针。
我唯一能想到的是使用placement new来分配和初始化。但是大多数C ++程序员甚至都不知道新的位置,所以我怀疑这个模糊的功能确实是寻找看似常见问题的方法。
那么,这里的正确策略是什么(假设堆栈分配不是一个选项)?