24

I came to know that smart pointer is used for resource management and supports RAII.

But what are the corner cases in which smart pointer doesn't seem smart and things to be kept in mind while using it ?

Ashish
  • 8,441
  • 12
  • 55
  • 92

10 Answers10

21

Smart pointers don't help against loops in graph-like structures.

For example, object A holds a smart pointer to object B and object B - back to object A. If you release all pointers to both A and B before disconnection A from B (or B from A) both A and B will hold each other and form a happy memory leak.

Garbage collection could help against that - it could see that both object are unreachable and free them.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 20
    *Strong* smart pointers in loops will cause memory to leak, but careful use of *weak* pointers (a part of any complete smart pointer library) allow you to effectively use smart pointers without leaks even with circular structures. – Sam Harwell Dec 15 '09 at 08:41
  • 1
    this is also related to a common leak with GC, when you have a circular structure and no longer need part of it you have to manually break the cycle to allow GC (or allow GC to collect the whole structure) e.g. c# events – jk. Dec 15 '09 at 08:51
  • 4
    @jk: Not quite the same thing. A GC can handle the case where A points to B and B points to A assuming no other object points to either object. You only have to "break the cycle" if there is still another reference to either A or B. So it's really not the cycle that's the problem. A half decent GC can handle those. The problem is when you create references from rarely used data to long-lived data, without realizing it (as in events). It has nothing to do with cycles. – jalf Dec 15 '09 at 12:32
  • 1
    "_Garbage collection could help against that - it could see that both object are unreachable and free them._" but not if the objects in the cycle need finalisation! (this is by definition) – curiousguy Nov 25 '11 at 06:36
11

I would like to mention performance limitations. Smart pointers usually use atomic operations (such as InterlockedIncrement in Win32 API) for reference counting. These functions are significantly slower than plain integer arithmetic.

In most cases, this performance penalty is not a problem, just make sure you don't make too many unnecessary copies of the smart pointer object (prefer to pass the smart pointer by reference in function calls).

Miroslav Bajtoš
  • 10,667
  • 1
  • 41
  • 99
  • 1
    Unless performance penalty becomes obvious, i'd advise against using references to smart pointers. When used as function arguments, it has no negative impact, but it may when used as class members. Beware ! – Benoît Dec 15 '09 at 08:16
  • 2
    @Benoit: I'm pretty sure "pass the smart pointer by reference" specifically means in calls, in which case you really shouldn't advise someone to pass it by value. – Sam Harwell Dec 15 '09 at 08:46
  • 2
    Yes, I meant passing it as an argument to a function. I have edited the reply to make it more clear. – Miroslav Bajtoš Dec 15 '09 at 10:15
  • 1
    It's also worth noting passing around raw pointers and failing to failing to use InterlockedIncrement or some other synchronization mechanism in a multithreaded application is unsafe. Given those constraints, in that context, ILCX is much faster than a lock, and much harder to get right. IMHO, this is a pro of smart pointers rather than a con – Andrew Walker Dec 15 '09 at 10:26
  • It was already clear when i commented on this answer. But it is difficult for unexperienced programmers to apply one rule for function arguments and another for class members. Hence my first comment. Since it's most of the time pointless to make that distinction, just don't until you find out that you need to. – Benoît Dec 15 '09 at 10:55
  • 3
    To be fair, shared pointers aren't the only kind of smart pointer. Other types of smart pointers avoid this performance penalty. – jalf Dec 15 '09 at 12:34
  • I've made VERY good use of scoped_ptr and a scoped_ptr specialization. Very handy for writing check-and-throw/return code. – KitsuneYMG Dec 18 '09 at 10:55
  • @Benoît programmers should not be confusing class members with function arguments. They might, but if they do then the main issue isn't when to use references. Function arguments should be passed by reference very often when possible. This *does* make a difference – That Realty Programmer Guy Aug 01 '19 at 04:24
6

This is quite interesting: Smart Pointers.
It's a sample chapter from "Modern C++ Design" by Andrei Alexandrescu.

Dana
  • 2,619
  • 5
  • 31
  • 45
5

Watch out at the transitions - when assigning between raw and smart pointers. Bad smart pointers - like _com_ptr_t - make it worse by allowing implicit conversions. Most errors happen at the transition.

Watch out for cycles - as mentioned, you need weak pointers to break the cycles. However, in a complex graph that's not always easy to do.

Too much choice - most libraries offer different implementations with different advantages / drawbacks. Unfortunately, most of the time these different variants are not compatible, which becomes a probem when mixing libraries. (say, LibA uses LOKI, LibB uses boost). Having to plan ahead for enable_shared_from_this sucks, having to decide naming conventions between intrusive_ptr, shared_ptr and weak_ptr for a bunch of objects sucks.


For me, the single most e advantage of shared_ptr (or one of similar functionality) is that it is coupled to its destruction policy at creation. Both C++ and Win32 offers so many ways of getting rid of things it's not even funny. Coupling at construction time (without affecting the actual type of the pointer) means I have both policies in one place.

peterchen
  • 40,917
  • 20
  • 104
  • 186
3

Beside technical limitations (already mentioned : circular dependencies), i'd say that the most important thing about smart pointers is to remember that it's still a workaround to get heap-allocated-objects deleted. Stack allocation is the best option for most cases - along with the use of references - to manage the lifetime of objects.

Benoît
  • 16,798
  • 8
  • 46
  • 66
  • Stack allocation most certainly is not the best option in most cases. Stack allocation has its own limitation and you hit them pretty quickly if you handle any reasonable number of data structures. Most complex programs use heap-allocation simply because you blow the stack pretty quickly when the numbers grow. Linux default is 8megs pr thread IIRC. On most embedded systems its in the kb range. – Morten Jensen Sep 05 '12 at 12:44
  • I see your point. But wouldn't you rather create specific container classes which allocate and deallocate their own chunks of memory than allocate memory blocks everywhere in your code and hope that you forgot no one ? This way, you can circumvent the stack-size problem... – Benoît Sep 05 '12 at 15:17
  • Sure we agree on that - that's what good C++ is all about in my opinion :) I was just arguing against your point that "stack allocation is the best option for most cases". – Morten Jensen Sep 05 '12 at 23:06
0

The following article is a very interesting paper

Smart Pointers: Can't Live With 'Em, Can't Live Without 'Em

Nadir SOUALEM
  • 3,451
  • 2
  • 23
  • 30
0

Here are a few things

  • There's no definite entity which destroys the object. Often it is desired to know exactly when and how an object is being destroyed
  • Circular dependencies - If they exist you'll have a memory leak. That's usually where weak_ptr come to the rescue.
shoosh
  • 76,898
  • 55
  • 205
  • 325
  • 1
    Usually it's sufficient to know that an object was destroyed, at more or less the appropriate time. I haven't run into many cases where I needed to know exactly when and in response to what. – David Thornley Dec 16 '09 at 20:20
  • 2
    The destruction of the object is guaranteed to take place in a well-defined place (even in the case of ref-counted smart pointers the destruction is guaranteed to occur at a well-defined place; it's just that with ref-counted smart pointers you don't know that place until runtime). – Max Lybbert Dec 16 '09 at 21:08
  • "_That's usually where weak_ptr come to the rescue._" usually not, `weak_ptr` can only hide the problem. – curiousguy Nov 25 '11 at 06:37
0

Raymond Chen is notoriously ambivalent about smart pointers. There are issues about when the destructor actually runs (please note, the destructor runs at a well-defined time in a well-defined order; it's just that once in a while you'll forget that it's after the last line in your function).

Also remember that "smart pointer" is a pretty big category. I include std::vector in that category (a std::vector is essentially a smart array).

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69
  • 6
    But something that "manages its own memory is just a "sane C++ class" and *nothing* more. It's the very least you should expect from *any* class. A smart pointer is one which manages *other peoples memory*. One which is given a pointer, and takes care of deleting it at the right time. And the destructor thing is nothing to do with smart pointers. It's a general thing in C++, and any C++ programmer had better know it by heart. – jalf Dec 15 '09 at 12:37
  • (1) Bjarne Stroustrup doesn't use the term "smart pointer" but he does note an equivalence in his FAQ: http://www2.research.att.com/~bs/bs_faq2.html#auto_ptr . (2) "Smart pointer" doesn't say anything about copy semantics. std::auto_ptr handles copy very differently from copying a normal pointer, but it's still a (very unpopular) smart pointer. (3) "Smart pointer" doesn't say anything about ownership either; compare shared pointers, weak pointers, and auto_ptr/scoped_ptr. – Max Lybbert Dec 16 '09 at 21:12
  • @MaxLybbert But **smart pointers have the same value semantic as regular pointers**: a smart pointer has a value that is independent of the value of the pointed-to object. That is why a smart pointer `operator*` is a `const` member function and returns a non-`const` pointer. – curiousguy Nov 25 '11 at 06:41
  • @curiousguy: You can bold your definition of "smart pointer," but that doesn't make it a universal truth. "Smart pointers" are a very large category and cover several implementations. Some of those implementations fit your definition, but there is no reason to believe that they all do. – Max Lybbert Nov 26 '11 at 06:16
  • @MaxLybbert a smart **pointer** is a class object that's supposed to act like a **pointer**, otherwise it wouldn't be called a smart **pointer**. – curiousguy Nov 26 '11 at 06:22
  • @curiousguy: `std::auto_ptr` is unquestionably a smart pointer, although it surprises programmers because it doesn't act all that much like a pointer. You'll need to try again. – Max Lybbert Nov 26 '11 at 06:27
  • 1
    @MaxLybbert Quoting myself: "`std::auto_ptr` has a value that is independent of the value of the pointed-to object. That is why `std::auto_ptr` `operator*` is a `const` member function and returns a non-`const` pointer." (Obviously, a smart point with exactly the semantic of a raw pointer would be ... a raw pointer.) – curiousguy Nov 26 '11 at 06:36
  • You are correct about the fact that move-like copy semantic of `auto_ptr` is at odds with the copy semantic of regular pointers. Reworded comment: a "smart pointer" is a class object that's supposed to act, _at least in some way_, like a pointer, otherwise it wouldn't be called a "smart pointer". – curiousguy Nov 26 '11 at 06:40
  • @curiousguy: My point is simply that the Standard doesn't define "smart pointer." Instead, it's a "I know it when I see it" argument. The fact that you have your own definition of "smart pointer" doesn't mean a whole lot to me. Does a smart pointer **have** to manage the memory pointed to? What about a class that only reports whether memory has been appropriately cleaned up before the destructor runs? Must a smart pointer overload `operator->` as well as `operator*`? I can find conflicting definitions all over the 'net, including those from C++ luminaries. – Max Lybbert Nov 26 '11 at 06:46
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/5363/discussion-between-curiousguy-and-max-lybbert) – curiousguy Nov 26 '11 at 06:56
  • That's a reasonable request, but frankly I don't care enough about the subject to spend any more time on it. – Max Lybbert Nov 26 '11 at 23:51
0

There is a problem with reference counting in certain types of data structures that have cycles. There can also be problems with accessing smart pointers from multiple threads, concurrent access to reference counts can cause problems. There's a utility in boost called atomic.hpp that can mitigate this problem.

James Thompson
  • 46,512
  • 18
  • 65
  • 82
0

Many people run into problems when using smart pointers mixed with raw pointers (to the same objects). A typical example is when interacting with an API that uses raw pointers.
For example; in boost::shared_ptr there is a .get() function that returns the raw pointer. Good functionality if used with care, but many people seem to trip on it.
IMHO it's an example of a "leaky abstraction".

Niklas
  • 5,736
  • 7
  • 35
  • 42