在 Effective C ++ 3 / E 中,我读到了这个:
这是异常不安全的代码:
class Test { };
void foo(const std::shared_ptr<Test> &ptr, int i);
int bar();
...
foo(std::shared_ptr<Test>(new Test), bar());
因为编译器可以这样实现:
- 运行
new Test
- 调用
bar()
&lt; - 如果bar()
抛出异常,则Test
分配的new Test
对象无法删除。- 调用
的构造函数std::shared_ptr<Test>
- 致电
醇>foo()
但在这种情况下,编译器可以知道存在内存泄漏。如果抛出异常,编译器无法自动执行delete
吗?
此外,在这种情况下,编译器会自动delete
:
Test *p = new Test;
这样实现:
- 致电
operator new
分配内存- 调用
醇>Test
的构造函数。 如果构造函数抛出异常,则会自动删除内存。
为什么编译器在第一种情况下没有做,与第二种情况不同?
答案 0 :(得分:4)
编译器通常不知道存在内存泄漏。
代码从Test
的构造函数返回后,
编译器必须假定该对象已完全和
正确构造,这可能(并且经常)意味着
构造函数已在某处注册了指向它的指针,并且
其他代码期望找到它。
标准可以指定异常将导致
delete
将在完整的新对象上调用{{1}}
它经过的表达。有许多历史
这个原因甚至没有被考虑过。今天,它会
可能会破坏太多的现有代码。
该标准也可以对该标准实施严格的排序 表达的评价。这将消除很多问题 未定义的行为,并使代码更具确定性(所以 测试更可靠)。从历史上看,C并没有采取这种做法 路线因其对优化的影响; C ++一直保持着 规则。