Never using
new
delete
release
and preferring to use
std::make_unique
std::unique_ptr
std::move
reset
(redundant)
should morally result in no memory leaks: new'ed pointers are only ever created inside smart pointers, from which they can never escape, because we have disallowed use of release
.
One may therefore be tempted into using this coding style, and then never bother checking for memory leaks again - no matter where exceptions may be thrown from, the RAII semantics of the smart pointers should always clean up any dangling pointers as the stack is unwound.
Except C++ is full of nasty surprises. From experience of having my assumptions repeatedly smashed by gotw, I can't help but think that there might be some corner-case which manages to cause a memory leak anyway. Even worse, there might be an obvious way of releasing ownership of the pointer other than release
itself. Or another smart pointer class without an explicit
constructor which could accidentally ingest the raw pointer obtained via get
, leading to double frees...
Are there any loopholes? If there are, can they be fixed by adding some more simple restrictions? (not allocating any memory doesn't count!) And if a set of coding guidelines that prevents all types of memory errors can be reached, would it be okay to completely forget about the details of memory management?
I thought cyclic references were only a problem with std::shared_ptr
...
struct X
{
std::unique_ptr<X> x;
};
void leak()
{
auto x = std::make_unique<X>();
x->x = std::move(x);
}
This can be fixed by ensuring that there is no cycle in the graph of types formed by adding an edge from A
to B
if and only if A
contains a member std::unique_ptr<C>
where C
is a base of B
.
struct evil {
std::shared_ptr<evil> p; // Alternatively unique_ptr
};
void foo() {
auto e = std::make_shared<evil>(); // Alternatively make_unique
e->p = e; // Alternatively std::move(e)
}
int main() {
for (unsigned i = 1; i != 0; ++i) {
foo();
if (i % 100000000)
std::cout << "I leak\n";
}
}
the above program obeys your restrictions, and leaks like a sieve.
On top of that, undefined behavior can cause leaks.
would it be okay to completely forget about the details of memory management?
I'd say the answer to this is going to be no in programming for the foreseeable future. Even in garbage collected languages today you can't forget about the details of memory management if you want a performant application.
Memory leaks still happen in garbage collected languages when programs accidentally hang onto references that are no longer needed. Following the rules you set out above for C++ would still be prone to the same issues and is even more likely to be an issue with uses of shared_ptr
. Common errors of this type are hanging on to objects in a container or through observers for managed references in a garbage collected language or shared_ptr
in C++.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With