In a statement, the order of evaluation of sub-expressions (e.g., the arguments of a function call) is not totally specified. This means the
compiler can even interleave the evaluation of these sub-expressions, especially for optimization purposes.
If you have several resource allocations in one statement, and the first succeeds while the second fails and throws an exception, the first
allocated resource can leak. The classical mitigation for this issue is to use an RAII (Resource Acquisition Is Initialization) manager to
wrap the raw resource. Yet, this solution may not be sufficient since the execution order is not specified.
It is possible to write code that contains several allocations and still behaves correctly. C++17 made this even easier since the evaluation order
rules are more strict. However, it requires expert-level knowledge of the language. It is simpler and more future-proof to simply avoid using several
allocations in a single statement.
Noncompliant code example
#include <memory>
class S {
public:
explicit S(int a, int b);
};
void g(std::shared_ptr<S> p1, std::shared_ptr<S> p2);
void f() {
g(std::shared_ptr<S>(new S(1, 2)), std::shared_ptr<S>(new S(3, 4))); // Noncompliant: 2 resources are allocated in the same expression statement
}
In this example, it would be valid for a pre-C++17 compiler to run the code in this order:
-
new S(1, 2) => p1
-
new S(3, 4) => p2
-
std::shared_ptr<S>(p1) => s1
-
std::shared_ptr<S>(p2) => s2
-
g(s1, s2)
In that case, if the second allocation fails, the memory allocated for the first one will be leaked since the shared_ptr
has not yet
been able to claim ownership of the object.
Compliant solution
#include <memory>
class S {
public:
explicit S(int a, int b);
};
void g(std::shared_ptr<S> p1, std::shared_ptr<S> p2);
void f() {
auto s = std::shared_ptr<S>(new S(1, 2));
g(s, std::shared_ptr<S>(new S(3, 4))); // Compliant, only one resource allocation, even if a bit messy
// Or, a better alternative:
g(std::make_shared<S>(1, 2), std::make_shared<S>(3, 4)); // Compliant: no explicit allocation
}