About the usage of new and delete, and Stroustrup\'s advice...
He says something like (but not exactly, this is from my notes of his book):
A rule
The way I think of it is that every resource should be owned by something. The owner is the one who is responsible for cleaning up. Usually this owner is a smart pointer of some kind, but even std::vector is an owner a resource: the block of memory which stores it's contiguous elements. This advice holds not just for memory but any resource such as file descriptors, database handles, mutexes, etc...
When you call new and delete manually in some part of your code that's not a wrapper class, you the programmer become the resource owner. With ownership comes the responsibility of cleaning up after yourself. Now you and all of the maintenance programmers who come after you have to ensure that all code paths after the new eventually lead to a delete. Even for simple functions this very is easy to get wrong. With exceptions, almost impossible unless you carefully wrap everything in try catch blocks, resulting runtime performance penalties and polluting your code with extra scopes and unnecessary exception logic. Finally, even if you do get it right, you just wasted a lot your time doing this tedious work of resource management. The compiler is tool which can do this work for you, use it.
The worst situation is when some subsystem allocates a resource, it gets passed around the application, and some other far away subsystem frees it. The number of possible code paths in this situation is intractable. It is very difficult if not impossible for a human being to reason about and trust. In my opinion, this style of programming is unmaintainable. How many C projects have you worked with in the past that are riddled with memory errors, especially on rarely if never executed error handling paths? I've dealt with more than I care to see anymore.
C has manual memory management, Java and others have garbage collection. C++ has RAII. It's as efficient as C and and almost as safe as garbage collection.
My rule is simple, if you find yourself manually cleaning up any resource, you have just written a bug.
It's a great rule. In fact, you can avoid using new
in arguments to smart pointers by using the appropriate make_
functions. For example, instead of:
std::shared_ptr<int> p(new int(5));
You can often do:
auto p = std::make_shared<int>(5);
This also has the benefit of being more exception safe. While a std::make_unique
doesn't yet exist, it is planned to make its way into C++14 (it is already in the working draft). If you want it now, there are some existing implementations.
You can go a step further and even avoid using new
and delete
in constructors and destructors. If you always wrap dynamically allocated objects in smart pointers, even when they're class members, you won't need to manage your own memory at all. See the Rule of Zero. The idea is that it's not the responsibility of your class to implement any form of ownership semantics (SRP) - that's what the smart pointers are for. Then you theoretically never have to write copy/move constructors, copy/move assignment operators or destructors, because the implicitly defined functions will generally do the appropriate thing.
Seems more like a poll than a question but here it goes: in application code I generally don't use new
at all. Due to our coding guidelines the code does use pointer but none of these "naked" pointers is actually transfering ownership. All objects are owned by some other object.
To be fair, when objects need to be allocated the allocation generally uses something morally equivalent to std::make_shared<T>(...)
which sometimes does show up in application code. One major reason for this rather thorough absence of new
(or similar) is that objects are generally allocated using stateful allocators and not doing so via a resource manager actually happens to be fairly complicated. Thus, there is little place for direct memory allocation using new
or a placement version thereof in application code.
In some infrastructure code, especially when creating custom containers the situation is slightly different: there is memory allocated (from allocators and initialized using placement new
) there. However, even there any result from memory allocation and initialization of objects is immediately passed on to resource managers. Basically, I can't cope with explicit resource management and using resource managers just reliefs me of the necessary work.