4

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());

因为编译器可以这样实现:

  1. new Test
  2. call bar() <--如果bar()抛出异常,Test分配者的对象new Test不能被删除。
  3. 调用构造函数std::shared_ptr<Test>
  4. 称呼foo()

但是在这种情况下,编译器可以知道存在内存泄漏。delete如果抛出异常,编译器不能自动执行吗?

此外,delete在这种情况下,编译器会自动执行:

Test *p = new Test;

是这样实现的:

  1. 调用operator new分配内存
  2. 调用构造函数Test如果构造函数抛出异常,内存会被自动删除。

为什么编译器在第一种情况下不做,不像第二种情况?

4

1 回答 1

4

编译器通常无法知道存在内存泄漏。一旦代码从 的构造函数返回Test,编译器必须假定该对象已完全正确构造,这可能(并且经常)意味着构造函数已在某处注册了指向它的指针,并且其他代码将期望找到它。

该标准可以指定一个异常将导致 delete在它通过的完整表达式中的所有新对象上调用。有许多历史原因甚至没有考虑到这一点。而今天,它可能会破坏太多现有代码。

该标准还可以对表达式的评估施加严格的顺序。这将消除许多未定义行为的问题,并使代码更具确定性(因此测试更可靠)。从历史上看,C 并没有走这条路线,因为它对优化有影响;C++ 保持了规则。

于 2014-04-25T10:58:42.633 回答