162

I read in a few articles that raw pointers should almost never be used. Instead they should always be wrapped inside smart pointers, whether it's scoped or shared pointers.

However, I noticed that frameworks like Qt, wxWidgets and libraries like Boost never return nor expect smart pointers, as if they were not using them at all. Instead, they return or expect raw pointers. Is there any reason for that? Should I stay away from smart pointers when I write a public API, and why?

Just wondering why smart pointers are recommended when many major projects seem to avoid them.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
laurent
  • 88,262
  • 77
  • 290
  • 428
  • 23
    All of those libraries you just named were started many years ago. Smart pointers only became truly standard in C++11. – chrisaycock Apr 26 '12 at 13:33
  • 24
    smart pointers do have an overhead (reference counting etc)- that may be critical - in embedded/real time systems for example. IMHO - smart pointers are for lazy programmers. Also lots of APIs go for the lowest common denominator. I feel the flames licking around my feet as I type! – Ed Heal Apr 26 '12 at 13:37
  • 96
    @EdHeal: The reason you can feel flames licking around your feet is because you're entirely wrong in every respect. For example, what overhead is there in `unique_ptr`? None whatsoever. Are Qt/WxWidgets targetted at embedded or real time systems? No, they're intended for Windows/Mac/Unix on a desktop- at most. Smart pointers are for programmers who want to get it correct. – Puppy Apr 26 '12 at 13:43
  • @EdHeal: Your remark regarding flames has my attention. If you can spare a minute, would you look at the answer I have posted below and advise me what is supposed to be wrong with it? It's downvoted without comment at the moment. I don't care much about the downvote as such, but if I've erred, I would like to know how. – thb Apr 26 '12 at 13:46
  • 1
    @DeadMG - The OP mentions libraries in general. The OP just pointed out a couple for consideration, but did not limit it to those. – Ed Heal Apr 26 '12 at 13:49
  • @DeadMG: Would you elaborate? I didn't know that `unique_ptr` lacked overhead, but then I haven't used a `unique_ptr` before. On the other hand, the question regarded smart pointers. Is a `unique_ptr` actually smart? – thb Apr 26 '12 at 13:49
  • 6
    @thb: A smart pointer is any class which holds a generic resource that guarantees correct cleanup. – Puppy Apr 26 '12 at 13:50
  • 4
    @DeadMG: Qt has been running on mobile phones for a few years now. – James Apr 26 '12 at 13:51
  • 2
    @James: Mobile phones are hardly embedded systems these days. The performance cost of a single-threaded reference count is pretty negligible, especially if you only have a few objects on your tiny screen. Not to mention the whole `unique_ptr` thing. – Puppy Apr 26 '12 at 13:53
  • 24
    Really, mobile phones are running Java. – R. Martinho Fernandes Apr 26 '12 at 13:57
  • @R.MartinhoFernandes case in point. Also, I write libraries much of the time and I use smart pointers whenever I can, so I guess it's just the fact that you have only read libraries that were started long ago and/or want to be compatible with older compilers. – Seth Carnegie Apr 26 '12 at 14:16
  • @Laurent - could you maybe clarify in your question which specific Boost library you are referring to?? – Martin Ba Apr 26 '12 at 16:55
  • 3
    [QSharedPointer](http://qt-project.org/doc/qt-4.8/qsharedpointer.html) – Inverse Apr 26 '12 at 19:29
  • 12
    Smart pointers only truly standard in C++11? What??? These things have been used for more than 20 years. – Kaz Apr 26 '12 at 20:03
  • 9
    @Kaz: But until now, `auto_ptr` as the only one in the Standard Library. – dan04 Apr 26 '12 at 21:11
  • 3
    So smart pointers are not "truly standard" until we have instances of them in the standard library, numbering two or more. I see. :) – Kaz Apr 26 '12 at 21:20
  • shared_ptr and intrusive_ptr are getting more and more popular, and they are certainly older than C++11, and I think I started using smart pointers before Y2K. Personally I need high performance for my app, so I use a variation on intrusive_ptr that implicitly converts to/from T* (so I can skip ref-counting easily.) I often use auto_ptr too, since its overhead is zero if the compiler is smart. I am not "lazy" by using smart pointers; to the contrary, they are essential for correctness since my app uses exceptions, and they are also essential to avoid accidental memory leaks since I am human. – Qwertie Apr 26 '12 at 23:08
  • GEB taught us the answer to such a question - "Mu". It's the answer to a non-question, a question that can't be asked because its statement is contradictory. Of course C++ libraries and frameworks use smart pointers. I can't believe Reddit hype made this question upvoted so many times. – Eli Bendersky Jan 06 '13 at 21:08
  • 2
    Actually VTK (http://www.vtk.org/) uses smartpointer and started in the early 90'ies. – NewProggie Jan 06 '13 at 19:19
  • 4
    @thb Absolutely a unique_ptr is smart. The 'smartness' is in its enforcement of ensuring uniqueness. And just like any other programmer, I make mistakes in copying something that really shouldn't be copied. Using a unique pointer ensures that I do things correctly and that the program works smartly. An example might be a pointer to a file stream. Copying it could incur synchronization issues. – Ben J Jul 08 '13 at 10:44

8 Answers8

128

Apart from the fact that many libraries were written before the advent of standard smart pointers, the biggest reason is probably the lack of a standard C++ Application Binary Interface (ABI).

If you’re writing a header-only library, you can pass around smart pointers and standard containers to your heart’s content. Their source is available to your library at compile time, so you rely on the stability of their interfaces alone, not of their implementations.

But because of the lack of standard ABI, you generally cannot pass these objects safely across module boundaries. A GCC shared_ptr is probably different from an MSVC shared_ptr, which too can differ from an Intel shared_ptr. Even with the same compiler, these classes are not guaranteed to be binary compatible between versions.

The bottom line is that if you want to distribute a prebuilt version of your library, you need a standard ABI on which to rely. C doesn’t have one, but compiler vendors are very good about interoperability between C libraries for a given platform—there are de facto standards.

The situation is not as good for C++. Individual compilers can handle interoperation between their own binaries, so you have the option of distributing a version for every supported compiler, often GCC and MSVC. But in light of this, most libraries just export a C interface—and that means raw pointers.

Non-library code should, however, generally prefer smart pointers over raw.

Jacob
  • 34,255
  • 14
  • 110
  • 165
Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
  • 18
    I agree with you, even passing a std::string can be a pain, This says a lot about C++ as a "great language for libraries". –  Apr 27 '12 at 05:56
  • 8
    The bottom line is more like: if you want to distribute a prebuild version you have to do so for every compiler you want to support. – josefx Apr 27 '12 at 08:17
  • 6
    @josefx: Yes this is sad but true, the only alternative is COM or a raw C interface. I wish the C++ comity would start worring for this kind of problems. I mean it's not like C++ is a new language from 2 years ago. – Robot Mess Apr 27 '12 at 09:16
  • The user can use a different implementation of STL even using the same compiler. – KindDragon Mar 25 '13 at 19:08
  • 3
    I downvoted because this is wrong. The ABI issues are more than managable in most cases. Whilst hardly user-friendly, ABI is also hardly insurmountable. – Puppy Jul 06 '13 at 12:09
  • @DeadMG: Right...I didn’t mean to imply the situation was impossible, just “not as good for C++” as for C. Do you have any suggestions for edits to make that clearer? – Jon Purdy Jul 06 '13 at 17:40
  • "Non-library code should, however, generally prefer smart pointers over raw." I think this should be the deciding factor. For those that are like "well how do you know the lifetime of the pointers?" That's called documentation and comments - the same way it's been done for years. – Natalie Adams Sep 12 '13 at 20:49
  • 1
    @NathanAdams: That’s absurd. If it’s not machine-checked, then in a nontrivial program it *will* be a source of bugs. – Jon Purdy Sep 13 '13 at 01:05
  • Would you consider Doom 3 engines to be a "nontrivial program"? If so - you better call John Carmack and let him know that there are bugs in his engine. Also people, like John Carmack (and/or his team) have already figured out how to debug heap issues - https://github.com/TTimo/doom3.gpl/blob/8047099afdfc5c973faa67a04f601a014de0fa73/neo/idlib/Heap.h . Arguably anything heap related should have some debug counter built in. But then there are tools such as valgrind, Dr. Memory etc - using a smart pointer doesn't mean that a memory leak won't happen it's just less likely. – Natalie Adams Sep 13 '13 at 04:12
  • 4
    @NathanAdams: Such software is undoubtedly impressive and useful. But it treats the symptom of deeper problems: C++ semantics of lifetime and ownership are somewhere between impoverished and nonexistent. Those heap bugs would not have arisen if the language did not allow them. So sure, smart pointers are not a panacea—they’re an attempt to recoup some of the losses incurred by using C++ in the first place. – Jon Purdy Sep 13 '13 at 06:06
39

There can be many reasons. To list few of them:

  1. Smart pointers became part of standard just recently. Till then they were part of other libraries
  2. Their primary use is to avoid memory leaks; many libraries don't have their own memory management; Generally they provide utilities and APIs
  3. They are implemented as wrapper, since they are actually objects and not pointers. Which has additional time/space cost, compared to raw pointers; The users of the libraries may not want to have such overheads

Edit: Using smart pointers is a completely developer's choice. It depends on various factors.

  1. In performance critical systems, you may not want to use smart pointers which generates overhead

  2. The project which needs the backward compatibility, you may not want to use the smart pointers which has C++11 specific features

Edit2 There is a string of several downvotes in the span of 24 hours because of below passage. I fail to understand why the answer is downvoted even though below is just an add-on suggestion and not an answer.
However, C++ always facilitates you to have the options open. :) e.g.

template<typename T>
struct Pointer {
#ifdef <Cpp11>
  typedef std::unique_ptr<T> type;
#else
  typedef T* type;
#endif
};

And in your code use it as:

Pointer<int>::type p;

For those who say that a smart pointer and a raw pointer are different, I agree with that. The code above was just an idea where one can write a code which is interchangeable just with a #define, this is not compulsion;

For example, T* has to be deleted explicitly but a smart pointer does not. We can have a templated Destroy() to handle that.

template<typename T>
void Destroy (T* p)
{
  delete p;
}
template<typename T>
void Destroy (std::unique_ptr<T> p)
{
  // do nothing
}

and use it as:

Destroy(p);

In the same way, for a raw pointer we can copy it directly and for smart pointer we can use special operation.

Pointer<X>::type p = new X;
Pointer<X>::type p2(Assign(p));

Where Assign() is as:

template<typename T>
T* Assign (T *p)
{
  return p;
}
template<typename T>
... Assign (SmartPointer<T> &p)
{
  // use move sematics or whateve appropriate
}
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 14
    On 3. *Some* smart pointers have additional time/space costs, others don't, including `std::auto_ptr` that has been part of the standard for a long time (and note, I do like `std::auto_ptr` as the return type for functions creating objects, even if it is almost useless everywhere else). In C++11 `std::unique_ptr` has no additional costs over a plain pointer. – David Rodríguez - dribeas Apr 26 '12 at 14:13
  • 1
    @DavidRodríguez-dribeas, I agree. But also to note that, `auto_ptr` are [deprecated](http://stackoverflow.com/a/6293154/514235) from C++11. And `std::unique_ptr` needs move sematics, which is C++11 dependent. My point for cost of smart pointer is in general however. – iammilind Apr 26 '12 at 14:15
  • 4
    Exactly... there is a nice symmetry on the appearance of `unique_ptr` and disappearance of `auto_ptr`, code targeting C++03 should use the later, while code targeting C++11 can use the former. Smart pointers are **not** `shared_ptr`, there are many standard and none standard, including proposals to the standard that were rejected as `managed_ptr` – David Rodríguez - dribeas Apr 26 '12 at 15:30
  • 2
    @iammilind, those are interesting points, but the funny thing is that if we end up using smart pointers, as apparently many would recommend, we end up creating code incompatible with major libraries. Of course, we can wrap/unwrap the smart pointers as needed but it seems like a lot of hassle and would create inconsistent code (sometime we deal with smart pointers, sometime not). – laurent Apr 29 '12 at 08:43
  • 7
    The statement that smart pointers have "additional time/space cost" is somewhat misleading; all of the smart pointers except `unique_ptr` incur runtime cost, but `unique_ptr` is by far the one that is most commonly used. The code sample you provide is also misleading, because `unique_ptr` and `T*` are entirely different concepts. The fact that you refer to both of them as `type` gives the impression that they can be swapped out for one another. – void-pointer Jan 06 '13 at 05:17
  • 12
    You cannot typedef like that, these types are not in any way equivalent. Writing typedefs like this is asking for trouble. – Alex B Jan 06 '13 at 08:58
  • 2
    -1: Can you even use it like `Pointer::type`? Thought you'd need to specify that it's a type, not a static member, like so: `typename Pointer::type`. Which is a minor factor really, compared to what others have pointed out - that it's VERY bad to do something like this. Use or don't use smart pointers, don't try to be clever like this. – ShdNx Jan 06 '13 at 12:26
  • @void-pointer, it's evident that `unique_ptr` and `T*` are different and I am not promoting it the other way. If you have 10000 places in your code where you use `T*` and if you want to use `unique_ptr` then will go and modify the declaration at every place? My code sample is just an example for how to achieve something without changing the actual code at larger extent. – iammilind Jan 07 '13 at 02:15
  • @AlexB, I don't understand why it's inviting trouble and what's wrong with it? – iammilind Jan 07 '13 at 02:16
  • @ShdNx, Yes you can use like that. You need `typename` only when you are using it inside `template`s and I don't have to state each and every corner case. This is just an example of how to interchange between a raw pointer and a smart pointer. – iammilind Jan 07 '13 at 02:18
  • 1
    @iammilind You cannot copy a `unique_ptr`, and you have to `delete` a raw pointer. – Alex B Jan 07 '13 at 02:58
  • @iammilind: my bad then. Thanks! I still agree with the others that it's just a very bad thing to do, but I've removed the -1. Edit: can't remove the -1 until the answer is edited. – ShdNx Jan 07 '13 at 03:53
  • @AlexB, see the edit. It seems that several downvotes in last 2 days have come due to the example I have demonstrated. That is *just* an idea, an add-on, not something related to the question directly. – iammilind Jan 08 '13 at 07:03
  • 2
    @iammilind If I were just starting to learn about smart pointers, I would find that code sample to be very misleading. The reason one may choose to use raw pointers instead `std::unique_ptr` is precisely because the former allows you to manage a resource that is not bound to any particular scope. Your code listing may lead people to believe that blindly substituting occurrences of `T*` for `std::unique_ptr` is acceptable. – void-pointer Jan 13 '13 at 07:14
  • @iammilind This doesn't stop you from accidentally copying a raw pointer or forgetting to call Destroy, Assign can leave you with with a dangling copy of a raw pointer, etc. The worst case, the code will work with smart pointers and *appear to work* with raw pointers. Mixing them in one code path with added complexity (as if C++ isn't complex enough already!) seems like an all-around bad idea, and a maintenance nightmare if it's in the public library interface. – Alex B Jan 19 '13 at 05:44
35

There are two issues with smart pointers (pre C++11):

  • non-standards, so each library tend to reinvent its own (NIH syndrom & dependencies issues)
  • potential cost

The default smart pointer, in that it is cost-free, is unique_ptr. Unfortunately it requires C++11 move semantics, which only appeared recently. All other smart pointers have a cost (shared_ptr, intrusive_ptr) or have less than ideal semantics (auto_ptr).

With C++11 around the corner, bringing a std::unique_ptr, one would be tempted to think that it is finally over... I am not so optimistic.

Only a few major compilers implement most of C++11, and only in their recent versions. We can expect major libraries such as QT and Boost to be willing to retain compatibility with C++03 for a while, which somewhat precludes the wide adoption of the new and shiny smart pointers.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
13

You shouldn't stay away from smart pointers, they have their use especially in applications where you have to pass a object around.

Libraries tend to either just return a value or populate a object. They don't usually have objects that need to be used in a lot of places, so there is no need for them to use smart pointers (at least not in their interface, they may use them internally).

I could take as example a library we have been working on, where after a few months of development I realized we only used pointers and smart pointers in a few classes (3-5% of all classes).

Passing variables by reference was enough in most places, we used smart pointers whenever we had a object that could be null, and raw pointers when a library that we used forced us to.

Edit (I can't comment because of my reputation): passing variables by reference is very flexible: if you want the object to be readonly you can use a const reference (you can still do some nasty casts to be able to write the object) but you get the maximum of protection possible (it's the same with smart pointers). But I do agree that it's much nicer to just return the object.

Robot Mess
  • 949
  • 1
  • 7
  • 31
  • I don't disagree, with you, exactly, but I will point out that there is a school of thought that deprecates the passing of *variable* references in most cases. I confess that I adhere to that school. I prefer functions not to modify their arguments. At any rate, as far as I know, C++'s variable references do nothing to prevent mishandling of the objects to which they refer, which is what smart pointers intend to do. – thb Apr 26 '12 at 14:09
  • 2
    you have const for that (seems I can comment :D). – Robot Mess Apr 26 '12 at 14:17
8

Qt pointlessly re-invented many parts of the Standard library in an attempt to become Java. I believe that it does actually have its own smart pointers now, but in general, it is hardly a pinnacle of design. wxWidgets, as far as I'm aware, was designed long before usable smart pointers were written.

As for Boost, I fully expect that they use smart pointers wherever appropriate. You might have to be more specific.

In addition, don't forget that smart pointers exist to enforce ownership. If the API has no ownership semantics, then why use a smart pointer?

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 19
    Qt was written before much of the functionality was sufficiently widespread on the platforms it wanted to use. It has had smart pointers for a long long time, and uses them to do the implicit sharing of resources in almost all Q* classes. – rubenvb Apr 26 '12 at 13:43
  • 6
    *Every* GUI library needlessly reinvents the wheel. Even strings, Qt has `QString`, wxWidgets has `wxString`, MFC has the horribly named `CString`. Isn't a UTF-8 `std::string` good enough for 99% of GUI tasks? – Inverse Apr 26 '12 at 19:43
  • 11
    @Inverse QString was created when std::string wasn't around. – MrFox Aug 02 '12 at 13:40
  • Check when qt was created and what smart pointers was available at that time. – Dainius Jan 08 '13 at 06:11
4

There are also other types of smart pointers. You might want a specialized smart pointer for something like network replication (one that detects if it's accessed and sends any modifications to the server or some such), keeps a history of changes, marks the fact that it was accessed so it can be investigated when you save data to disk and so on. Not sure if doing that in the pointer is the best solution but using the built in smart pointer types in libraries could result in people being locked into them and loosing the flexibility.

People can have all kinds of different memory management requirements and solutions beyond smart pointers. I might want to manage memory myself, I could be allocating space for things in a memory pool so it's allocated in advance and not at runtime (useful for games). I might be using a garbage collected implementation of C++ (C++11 makes this possible although none exist yet). Or maybe I'm just not doing anything advanced enough to worry about bothering with them, I can know that I'm not going to forget to uninitialized objects and so on. Maybe I'm just confident in my ability to manage memory without the pointer crutch.

Integration with C is another issue too.

Another issue is smart pointers are part of the STL. C++ is designed to be usable without the STL.

David C. Bishop
  • 6,437
  • 3
  • 28
  • 22
3

Good question. I don't know the specific articles to which you refer, but I have read similar things from time to time. My suspicion is that the writers of such articles tend to harbor a bias against C++-style programming. If the writer programs in C++ only when he must, then returns to Java or such as soon as he can, then he doesn't really share the C++ mindset.

One suspects that some or most of the same writers prefer garbage-collecting memory managers. I don't, but I think differently than they do.

Smart pointers are great, but they have to keep reference counts. The keeping of reference counts bears costs -- often modest costs, but costs nonetheless -- at runtime. There is nothing wrong with saving these costs by using bare pointers, especially if the pointers are managed by destructors.

One of the excellent things about C++ is its support for embedded-systems programming. The use of bare pointers is part of that.

Update: A commenter has correctly observed that C++'s new unique_ptr (available since TR1) does not count references. The commenter also has a different definition of "smart pointer" than I have in mind. He may be right about the definition.

Further update: The comment thread below is illuminating. All of it is recommended reading.

thb
  • 13,796
  • 3
  • 40
  • 68
  • 2
    For a start, embedded-systems programming is a vast minority of all programming, and quite irrelevant. C++ is a general-purpose language. Secondly, `shared_ptr` keeps a reference count. There are many other smart pointer types which do not keep a reference count at all. Finally, the libraries mentioned are targetted at platforms which have plenty of resources to spare. Not that I was the downvoter, but all I'm saying is that your post is full of wrong. – Puppy Apr 26 '12 at 13:49
  • 2
    @thb - I agree with you sentiment. DeadMG - Please try to live without embedded systems. Yes - some smart pointers do not have an overhead, but some do. The OP mentions libraries. Boost for example has parts that are used by embedded systems - but smart pointers may be inappropriate for certain applications. – Ed Heal Apr 26 '12 at 13:53
  • 2
    @EdHeal: Not living without embedded systems != programming for them is not a tiny, irrelevant, minority. Smart pointers are appropriate for every situation in which you need to manage the lifetime of a resource. – Puppy Apr 26 '12 at 13:54
  • 4
    `shared_ptr` has no overhead. It only has overhead if you don't need thread-safe shared ownership semantics, which is what it provides. – R. Martinho Fernandes Apr 26 '12 at 14:04
  • 1
    No, shared_ptr has significant overhead over the minimum necessary for thread-safe shared ownership semantics; specifically it allocates a heap block separate from the actual object you are sharing, for the sole purpose of storing the refcount. intrusive_ptr is more efficient, but (like shared_ptr) it also assumes that every pointer to the object will be an intrusive_ptr. You can get even lower overhead than intrusive_ptr with a custom ref-counting shared pointer, as I do in my app, and then use T* whenever you can guarantee that at least one smart pointer will outlive the T* value. – Qwertie Apr 26 '12 at 23:22
  • I wouldn't say embedded systems are irrelevant, but surely C is the language of choice there, and in C++ no doubt there are cases where smart pointers make sense in embedded, assuming the compiler optimizes as well as a typical x86 or ARM compiler. – Qwertie Apr 26 '12 at 23:25
0

It also depends on what domain you work in. I write game engines for a living, we avoid boost like the plague, in games the overhead of boost isn't acceptable. In our core engine we ended up writing our own version of stl (Much like the ea stl).

If i was to write a forms application, i might consider using smart pointers; but once memory management is second nature not having granular control over memory becomes quiet annoying.

slaphappy
  • 6,894
  • 3
  • 34
  • 59
Ugly Davis
  • 37
  • 3
  • 3
    There is no such thing as the "overhead of boost". – curiousguy May 19 '13 at 15:44
  • 4
    I've never had shared_ptr slow down my game engine to any noteworthy degree. They have sped up the production and debugging process though. Also, what exactly do you mean by "the overhead of boost?" That's a pretty large blanket to cast. – derpface May 19 '13 at 21:10
  • @curiousguy: It's the compilation overhead of all those headers and macro+template voodoo... – einpoklum May 09 '15 at 19:50