14

More and more I hear, that I should use smart pointers instead of naked pointers, despite I have effective memory leak system implemented.

What is the correct programming approach on using smart pointers please? Should they really be used, even if I check memory leaks on allocated memory blocks? Is it still up to me? If I do not use them, can this be considered as programming weakness?

If the smart pointers(ex: std::auto_ptr) are strongly recommended, should I use them instead of every naked pointer?

Bunkai.Satori
  • 4,698
  • 13
  • 49
  • 77
  • 2
    `std::auto_ptr` is deprecated. – Mahesh May 26 '11 at 16:47
  • 5
    Whatever you do, you certainly shouldn't use `std::auto_ptr` in place of every naked pointer. – NPE May 26 '11 at 16:49
  • 2
    As others have noted, `std::auto_ptr` is not recommended because it is not very "smart": when you assign one `auto_ptr` to another, you transfer ownership of the object that is pointed to. This is often not the behavior you want. If you want to use smart pointers, consider `boost::shared_ptr` instead. – Chris Frederick May 26 '11 at 16:50
  • 2
    @Chris: @aix: Just like blindly using std::auto_ptr is wrong blindly using boost::shared_ptr is also wrong. Use the correct smart pointer for the correct task. When transfer of ownership is useful then auto_ptr is great (though unique_ptr is now preferred (iff you have a newer compiler)). – Martin York May 26 '11 at 17:10
  • @Martin Absolutely. I just wanted to point out that the behavior of `auto_ptr` is not very intuitive. At least, it wasn't for me when I first learned about it. – Chris Frederick May 26 '11 at 17:15
  • Should we have a `naked-pointer` tag? :) – fredoverflow May 26 '11 at 19:43
  • @all: Dear all, thanks for your comments. I added +1 to valuable ones. I know, that I am going to port the application to two platforms: **Android, iOS**. Which smart pointer library to use then? Will **Boost::shared_ptr** work everywhere? – Bunkai.Satori May 26 '11 at 20:34

9 Answers9

22

You should use RAII to handle all resource allocations.

Smart pointers are just one common special case of that rule.

And smart pointers are more than just shared_ptr. There are different smart pointers with different ownership semantics. Use the one that suits your needs. (The main ones are scoped_ptr, shared_ptr, weak_ptr and auto_ptr/unique_ptr (prefer the latter where available). Depending on your compiler, they may be available in the standard library, as part of TR1, or not at all, in which case you can get them through the Boost libraries.

And yes, you should absolutely use these. It costs you nothing (if done correctly, you lose zero performance), and it gains you a lot (memory and other resources are automatically freed, and you don't have to remember to handle it manually, and your code using the resource gets shorter and more concise)

Note that not every pointer usage represents some kind of resource ownership, and so not all raw pointer usage is wrong. If you simply need to point to an object owned by someone else, a raw pointer is perfectly suitable. But if you own the object, then you should take proper ownership of it, either by giving the class itself RAII semantics, or by wrapping it in a smart pointer.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • 1
    "You should use RAII to handle all resource allocations." I'd go along with that, but most objects aren't resources in the classical sense. They're an intimate part of the program logic. Obviously, the object lives in underlying memory (which is a resource), but that resource clearly is owned by the object itself, and not by anyone else. – James Kanze May 26 '11 at 18:01
  • @jalf: +1, Hi Jalf. Thanks for your very valuable advice. Being sensitive to object ownership when deciding for the right smart pointer type is new to me, and since now, I will be aware of it. If you know, that you would port your application to Android and iOS, **what** Smart pointer **library** would you decide for? – Bunkai.Satori May 26 '11 at 20:41
  • @James: I'm not sure I see the distinction. Memory is a resource too. And every resource is a part of the program logic, isn't it? Dynamically allocated memory should be treated the way you'd treat any other resource. As something that is owned and managed using some flavor of RAII. Objects which don't need any dynamically allocated memory obviously don't have anything that needs managing, so they're irrelevant in this discussion. Am I missing something in your comment? – jalf May 26 '11 at 22:20
  • @jalf Memory can be considered a resource, but if it is a resource, it clearly belongs to the object residing in it (at least where class types with behavior are concerned), and that object should thus be responsible for freeing it. Treating that object as a resource is reversing the logical dependency. The object has a lifetime which is determined by the program logic; it is the program logic which determines when it should be deleted, and not whether some random other object still holds a pointer to it. – James Kanze May 27 '11 at 11:38
  • @James: but the program logic determines whether or not some random object still holds a pointer to it. That's the point in any kind of RAII/SBRM/whateveryouwanttocallit. `std::vector` holds a resource: the dynamically allocated array. And its lifetime determines the lifetime of the resource. In the case of `shared_ptr` and `weak_ptr`, the same principle applies, although the ownership semantics are more complex, and no *single* smart pointer alone determines the lifetime of the resource. – jalf May 27 '11 at 12:23
  • @jalf First, to be completely clear, `boost::shared_ptr` does *not* implement RAII. The single identifying characteristic of RAII (despite its name) is that the resource is freed when the object is destructed. And memory isn't a resource like another, in general, because it is part of the program---it can contain references to other memory, ad infinitum---and because it is largely managed automatically. It is, in fact, managed fully automatically in the cases where RAII is appropriate; that is, when the resource should be freed, unconditionally, when leaving scope. – James Kanze May 30 '11 at 10:55
10

You can't just blindly substitute std::auto_ptr for every raw pointer. In particular, auto_ptr transfers ownership on assignment, which is great for some purposes but definitely not for others.

There is a real reason there are several varieties of smart pointers (e.g., shared_ptr, weak_ptr, auto_ptr/unique_ptr, etc.) Each fulfills a different purpose. One major weakness of a "raw" pointer is that it has so many different uses (and has that versatility largely because it does little or nothing to assist in any one purpose). Smart pointers tend to be more specialized, which means they can be more intelligent about doing one thing well, but also means you have to pick the right one for the job or it'll end up dong the wrong things entirely.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • +1 This is the first intelligent comment about smart pointers I've heard in a long time. It makes me wonder if it isn't a good idea to use them more. Not necessarily the existing ones, but e.g. a smart pointer which doesn't allow incrementation, and whose name indicates that the object itself will be responsible for its destruction. – James Kanze May 26 '11 at 18:03
  • +1, hi Jerry. Thanks for your response. I understand that secetion of appropriate smart pointer type is important. There can be cases, where naked pointer is the most suitable as well. – Bunkai.Satori May 26 '11 at 20:51
4

Should they really be used, even if I check memory leaks on allocated memory blocks?

YES
The whole purpose of smart pointers is, it help you implement RAII(SBRM), which basically lets the resource itself take the responsibility of its deallocation and the resource doesn't have to rely on you explicitly remembering to deallocate it.

If I do not use them, can this be considered as programming weakness?

NO,
It is not a weakness but a inconvenience or unnecessary hassle to explicitly manage the resources by yourself if you are not using Smart pointers(RAII). The purpose of smart pointers to implement RAII is to provide efficient and hassle free way of handling resources and you would just not be making use of it if you are not using it. It is highly recommended to use it purely for the numerous advantages it provides.

If the smart pointers(ex: std::auto_ptr)are strongly recommended, should I use them instead of every naked pointer?

YES
You should use smart pointers wherever possible because simply there is no drawback of using them and just numerous advantages to use them.
Don't use auto_ptr though because it is already deprecated!! There are various other smart pointers available that you can use depending on the requirement. You can refer the link above to know more about them.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • RAII is one major purpose, but certainly not the sole or whole purpose. – Jerry Coffin May 26 '11 at 16:55
  • @Jerry, @jalf: Added a nice link which tries to list down the numerous advantages. – Alok Save May 26 '11 at 16:59
  • For one example, weak pointers allow non-owning access to data. Yes, they're used in conjunction with a shared pointer that's (sort of) oriented toward SBRM, but even that's rather a stretch. The weak pointer itself, however, definitely does *not* do stack-based resource management (since it's non-owning, it doesn't manage the resource at all, in fact). – Jerry Coffin May 26 '11 at 17:00
  • 1
    @Jerry: I'd say it participates in managing the resource's lifetime and ownership. (it keeps the ref counter alive, even if it doesn't manage the pointed-to resource). And it clearly uses its (stack-based) scope to do this – jalf May 26 '11 at 17:05
  • @jalf: at least IMO, you're stretching the point quite a bit to include it -- to the point that you simply render the term "SBRM" next to meaningless. – Jerry Coffin May 26 '11 at 17:08
  • It is usually preferential to use smart pointers. But doing so blindly can lead to its own problems. So not all RAW pointers should be replaced (by I would agree that for a beginner that is an easy starting point). – Martin York May 26 '11 at 17:13
  • @Martin: Agreed, the link in the answer is to a very popular Q here in C++ So, which nicely explains in detail each smart pointer and when to use it. – Alok Save May 26 '11 at 17:16
  • 1
    @Als: I disagree on the weakness point. Code that use manual memory management is more brittle than code that use automatic memory management. As such, *it is weaker*. – Matthieu M. May 26 '11 at 17:23
  • @Als: +1, hi and thanks for your high value response. I will avoid using `std::auto_ptr`. As you and other recommend, I will get used to using smart pointers of appropriate type to appropriate object ownership. – Bunkai.Satori May 26 '11 at 20:49
4

Smart pointers allows to define automatically the life-time of objects it refers to. That's the main thing to understand.

So, no, you shouldn't use smart pointers everywhere, only when you want to automate life-time of your objects instead of having, for example, an object managing those objects inside from birth to death. It's like any tool : it solves specific kind of problems, not all problems.

For each object, you should think about the life cycle it will go through, then choose one of the simplest correct and efficient solution. Sometimes it will be shared_ptr because you want the object to be used by several components and to be automatically destroyed once not used anymore. Sometimes you need the object only in the current scope/parent-object, so scoped_ptr might be more appropriate. Sometimes you need only one owner of the instance, so unique_ptr is appropriate. Maybe you'll find cases where you know an algorithm that might define/automate the lifetime of an object, so you'll write your own smart pointer for it.

For example of opposite case, using pools forbids you to use smart_ptr. Naked pointers might be a more welcome simple and efficient solution in this particular (but common in embedded software) case.

See this answer (from me) for more explainations : https://softwareengineering.stackexchange.com/questions/57581/in-c-is-it-a-reflection-of-poor-software-design-if-objects-are-deleted-manuall/57611#57611

Community
  • 1
  • 1
Klaim
  • 67,274
  • 36
  • 133
  • 188
  • +1 for very valuable answer. Hi Klaim, thanks. You and many other people mentioned, that the selection of correct smart pointer is very important. **Are you aware of a C++ library, that could be used safely on every target, I decide to port my application to?** – Bunkai.Satori May 26 '11 at 20:55
  • @Bunkai.Satori: I'm not sure what you're asking exactly. Do you mean a standard library or a smart pointer library? I'm using both the compiler-provided Standard Library and Boost (http://boost.org) on my C++ projects. Boost provide shared_ptr, scoped_ptr and maybe others I don't know about. – Klaim May 27 '11 at 08:24
  • Hi, Klaim. Let me explain. Standard Library is part of C++ and would therefore work on every C++ compiler, if I am correct. I know, that I will port my application to iOS and Android, however, Standard Library does not contain usable Smart Pointers, as `std::smart_ptr` is deprecated. My question therefore was, if you are aware that **Boost** or any other library, which havs efficient smart pointers would, work on **iOS** and **Android**. – Bunkai.Satori May 27 '11 at 10:31
  • @Bunkai.Satori: Ok, so first thing, std::smart_ptr don't exist. However std::shared_ptr does exist, BUT, it have been defined in the Technical Report 1 (TR1), a big patch to the current language standard. It is included in the new coming standard C++2011 (C++0x). So, if your compiler don't provide std::shared_ptr or std::tr1::shared_ptr, (gcc does provide it, MSVC10 too), then you'll have to get it from boost (that should work on any C++ compiler). If boost don't work on Android and iOS, you certainly have a buggy compiler. If you use gcc, you need to activate C++0x (see the gcc command line) – Klaim May 27 '11 at 12:33
4

If the smart pointers(ex: std::auto_ptr) are strongly recommended, should I use them instead of every naked pointer?

In my opinion, yes, you should it for every pointer that you own.

Here are my ideas on resource management in C++ (feel free to disagree):

  1. Good resource management requires thinking in terms of ownership.
  2. Resources should be managed managed by objects (RAII).
  3. Usually single ownership is preferred over shared ownership.
  4. Ideally the creator is also the owner of the object. (However, there are situations where ownership transfer is in order.)


This leads to the following practices:

  1. Make boost::scoped_ptr the default choice for local and member variables. Do keep in mind that using scoped_ptr for member variables will make your class non-copyable. If you don't want this see next point.

  2. Use boost::shared_ptr for containers or to enable shared ownership:

    // Container of MyClass* pointers:
    typedef boost::shared_ptr<MyClass> MyClassPtr;
    std::vector<MyClassPtr> vec;

  3. The std::auto_ptr (C++03) can be used for ownership transfer. For example as the return value of factory or clone methods:

    // Factory method returns auto_ptr
    std::auto_ptr<Button> button = Button::Create(...);

    // Clone method returns auto_ptr
    std::auto_ptr<MyClass> copy = obj->clone();

    // Use release() to transfer the ownership to a scoped_ptr or shared_ptr
    boost::scoped_ptr<MyClass> copy(obj->clone().release());

  4. If you need to store a pointer that you don't own then you can use a raw pointer:

    this->parent = inParentObject;

  5. In certain situations a boost::weak_pointer is required. See the documentation for more information.

StackedCrooked
  • 34,653
  • 44
  • 154
  • 278
  • +1, hi. Thanks very much for your detailed answer. I understand the points above, and they were valuable in understanding the correct usage of smart pointers. I will need to study them all in detail anyway :-) – Bunkai.Satori May 26 '11 at 20:58
4

It's a tricky question, and the fact that there is currently a mode to use smart pointers everywhere doesn't make things any easier. Smart pointers can help in certain situations, but you certainly can't just use them everywhere, without thinking. There are many different types of smart pointers, and you have to think about which one is appropriate in every case; and even then, most of your pointers (at least in typical applications in the domains I've worked in) should be raw pointers.

Regardless of the approach, several points are worth mentionning:

  • Don't use dynamic allocation unless you have to. In many applications, the only things that need to be allocated dynamically are objects with specific lifetimes, determined by the application logic. Don't use dynamic allocation for objects with value semantics.

  • With regards to entity object, those which model something in the application domain: these should be created and destructed according to the program logic. Irregardless of whether there are pointers to them or not. If their destruction causes a problem, then you have an error in your program logic somewhere (not handling an event correctly, etc.), and using smart pointers won't change anything.

A typical example of an entity object might be client connection in a server, is created when the client connects, and destructed when the client disconnects. In many such cases, the most appropriate management will be a delete this, since it is the connection which will receive the disconnection event. (Objects which hold pointers to such an object will have to register with it, in order to be informed of its destruction. But such pointers are purely for navigation, and shouldn't be smart pointers.)

What you'll usually find when people try to use smart pointers everywhere is that memory leaks; typical reference counters don't handle cycles, and of course, typical applications are full of cycles: a Connection will point to the Client which is connected to it, and the Client will contain a list of Connection where it is connected. And if the smart pointer is boost::shared_ptr, there's also a definite risk of dangling pointers: it's far to easy to create two boost::shared_ptr to the same address (which results in two counters for the references).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • +1, Hi James. Thanks very much for your detailed answer. It provides additional information aparto from the above, weithout repeating what others have mentioned. Yes, Dynamic Allocation can cause complications, but sometimes it is really the best choice to do. Especially, the last paragraph sounds, like I should perform my own garbage collection, withou using smart pointers at all :-) – Bunkai.Satori May 26 '11 at 21:05
  • @Bunkai Satori No. Use smart pointers where appropriate (which isn't everywhere). But in many cases, I find myself wanting something like a reverse garbage collection. Rather than wanting to delete something because there are no more pointers to it, the program logic says that the object must be deleted, and I'd like to get rid of all of the pointers to it:-). – James Kanze May 27 '11 at 11:29
2

Yes. Assuming you have C++0x available to you, use unique_ptr or shared_ptr (as appropriate) to wrap all the raw pointers you new up. With the help of make_shared, shared_ptr is highly performant. If you don't need reference counting then unique_ptr will get you better perf. Both of them behave properly in collections and other circumstances where auto_ptr was a dumb pointer.

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
  • Try using `shared_ptr` that way, and you're almost guaranteed dangling references (unless you've got a trick to make `this` a `shared_ptr`) and memory leaks due to cycles. – James Kanze May 26 '11 at 18:05
  • +1, Hi Kate. Thanks for your comment. Especially the `make_shared` is new to me and I will definitelly check it. – Bunkai.Satori May 26 '11 at 21:08
  • @James: if I understand correctly, you say, that using `shared_ptr` on objects created via `new()` is not recommended approach? – Bunkai.Satori May 26 '11 at 21:09
  • @Bunkai Satori Expecting `shared_ptr` to solve all of your problems, and using it for every `new` without thinking, is not the recommended approach. There are cases where it can be very useful. But it also has serious limitations, which have to be taken into account. And in many cases, it really doesn't buy you much; most dynamic allocation is (or should be) for entity objects whose lifetime is determined by the application design. No need for `shared_ptr` there. – James Kanze May 27 '11 at 11:33
2

In general you should prefer smart pointers, but there are a couple of exceptions.

If you need to recast a pointer, for example to provide a const version, that becomes nearly impossible with smart pointers.

Smart pointers are used to control object lifetime. Often when you are passing a pointer to a function, the function will not affect the lifetime; the function does not try to delete the object, and it does not store a copy of the pointer. The calling code cannot delete the object until the function returns. In that case a dumb pointer is perfectly acceptable.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • +1 for additional information. Hi Mark. Thanks for your comment. If I understand correctly, after I pass a `smart_pointer` to the function, the function **must not** change the life of the object, by deleting it. I can do so after the function returns back to the calling code. Althouth I do not get it now, is that correct, please? – Bunkai.Satori May 26 '11 at 21:13
  • @Bunkai.Satori, if you are using smart pointers then the smart pointer class will control the object lifetime; you are correct that you can't delete it, the smart pointer will do that automatically when the object is no longer needed. That was not the point of my statement though, I meant to say that most functions do not attempt to control object lifetime. If that is the case, you may safely pass a dumb pointer to the function rather than a smart pointer. – Mark Ransom May 26 '11 at 21:42
0

Using smart pointers (shared_ptr or otherwise) EVERYWHERE is a bad idea. It's good to use shared_ptr to manage the lifetime of objects/resources but it's not a good idea to pass them as parameters to functions etc. That increases the likelihood of circular references and other extremely hard to track bugs (Personal experience: Try figuring out who should not be holding onto a resource in 2 millions lines of code if every function invocation changes the reference count - you will end up thinking the guys who do this kind of thing are m***ns). Better to pass a raw pointer or a reference. The situation is even worse when combined with lazy instantiation. I would suggest that developers should know the lifecycle of the objects they write and use shared_ptr to control that (RAII) but not extend shared_ptr use beyond that.

Sean
  • 1
  • 1