In Effective C++ 3/E, I read this:
This is exception unsafe code:
class Test { };
void foo(const std::shared_ptr<Test> &ptr, int i);
int bar();
...
foo(std::shared_ptr<Test>(new Test), bar());
Because compiler can implement like this:
- run
new Test
- call
bar()
<-- ifbar()
throws exception, the object ofTest
allocated bynew Test
cannot be deleted.- call constructor of
std::shared_ptr<Test>
- call
foo()
But in this case, compiler can know there's memory leak. Can't compiler do delete
automatically if exception is thrown?
In addition, compiler does automatically delete
in that case:
Test *p = new Test;
that is implemented like this:
- call
operator new
to allocate memory- call constructor of
Test
. If constructor throws exception, memory is automatically deleted.
Why compiler doesn't do in first case, unlike second case?
The compiler cannot normally know that there is a memory leak.
Once the code returns from the constructor of Test
, the
compiler must assume that the object has been fully and
correctly constructed, which could (and often does) mean that
the constructor has registered a pointer to it somewhere, and
that other code will expect to find it.
The standard could have specified that an exception will cause
delete
to be called on all objects newed in the complete
expression it passes through. There are a number of historical
reasons why this wasn't even considered. And today, it would
probably break too much existing code.
The standard also could have imposed a strict ordering on the evaluation of an expression. This would remove a lot of issues of undefined behavior, and make code more deterministic (so tests are more reliable). Historically, C didn't take this route because of its impact on optimization; C++ has kept the rule.