Failure to do this can lead to subtle resource leaks when exceptions are thrown.
Suppose there’re two functions:
|
|
Apparently, following code won’t compile:
|
|
This is because tr1::shared_ptr
’s constructor taking a raw is explicit
, there’s no implicit conversion from the raw pointer (returned by new Widget
) to the tr1::shared_ptr
(required by processWidget
).
However, even though the code below does compile, seems correct, and carefully uses shared_ptr
to manage resource, it may still leak resources:
|
|
The two arguments as function parameters must be evaluated before a call to processWidget
is generated, and the first argument actually consists of two parts:
- execution of the expression
new Widget
- call to the
tr1::shared_ptr
constructor
Thus, before processWidget
can be called, following three steps must take place:
- Call
priority
- Execute
new Widget
- Call the
tr1::shared_ptr
constructor
Unlike Java and C#, where function parameters are always evaluated in a particular order, C++ compilers are free to decide the order of steps above. Although new Widget
must take place before tr1::shared_ptr
constructor can be call (for the result of new
operation is the argument of the smart pointer’s constructor), the call to priority()
can be performed first, second, or third. If compilers choose to perform it second (maybe for efficiency consideration):
- Execute
new Widget
- Call
priority
- Call
tr1::shared_ptr
constructor
The problem here is that, once the call to priority
yields an exception, the pointer returned from new Widget
has not turned over to the resource-managing object, and resource leaks.
Luckily, it is very simple to avoid this problem: use a separate statement to create Widget
and store it in a smart pointer, then pass the smart pointer to processWidget
:
|
|
Now the new Widget
expression and the call to tr1::shared_ptr
constructor are in a different statement from the call to priority
, compilers are not allowed to move the call to priority
between them.