Location
  • United Kingdom

Top Contributors

The case (or otherwise) for using smart pointers

Long story short, Sara and I started discussing the pros and cons of using smart pointers in C++ in the following thread...

http://www.experts-exchange.com/Programming/Languages/CPP/Q_28320852.html

I've already stated my opinion and have no desire to repeat myself but I've opened this discussion in case anyone else wants to opine either for or against. Since the question may be deleted (due to clean up), below are the comments that lead to the discussion:


evilrix 2015-05-14 at 19:08:41ID: 40777549

I was just cleaning this when I read: "a number of experts on this site critique code saying that they highly recommend that STL containers should not hold pointers."

The rational behind this is that under normal circumstances you are allocating object on the heap if you are going to store them in a container (otherwise you have going to have to store them all on the stack). Storing raw pointers is a bad idea because it make cleaning up hard. The code becomes brittle, and it's too easy to end up leaking memory. The safer (and preferred) solution is to use a smart pointer.

Of course, it might be the items are already in another container but then that brings into question issues of object ownership. Which container is responsible for cleaning up? Again, the safer (and preferred) solution is to use a smart pointer.

I will now proceed with cleaning this question :)

sarabande 2015-05-15 at 10:26:48ID: 40778715

Storing raw pointers is a bad idea because it make cleaning up hard. The code becomes brittle, and it's too easy to end up leaking memory. The safer (and preferred) solution is to use a smart pointer.

i like this statement but it is not true. any non-trivial enhancement of a container of the standard library necessarily would need to store (raw) pointers since c/c++ neither allows to store references nor to store different objects in one container. if you take for example a container which stores the objects read from a sql table and wants to provide an index of two of the columns the table has, the most simplest "container" to achieve that is a std::vector to store all the raw pointers and two std::map with <key, pointer> pair, one for each index. of course, the std::vector is the one who cares for cleaning at destruction time what isn't hard to accomplish and won't end in memory leaks. and of course using smart pointers instead would be possible but is an overkill, since both creation of objects in this new container and the safe deletion of its elements is well encapsulated and safe. smart pointers come to play if you don't know how many copies of your pointers were created but that isn't the case here. other containers, say your own string class, also would use a pointer to std::string internally rather than to derive from std::string, since the standard containers don't have virtual functions and it makes less sense to derive from them.

the key concept to avoid the dire consequences evilrix has pointed out, is to make a full container which provides all functionality needed by itself and would not unveil its internals.

Sara

evilrix 2015-05-15 at 10:35:20ID: 40778721

Sara, I was talking in the general sense for the general case. Of course, there are always exceptions, but in the general case, heap allocations to a container are best managed using smart pointers.

Especially if you want your code to be exception safe.

sarabande 2015-05-15 at 10:52:44ID: 40778741

but the question here was Query/Maintain a container having two independent keys

so it is exactly a classic example for creating an own container class based on standard containers (and using pointers internally to avoid copies). as told you could use smart pointers (or your own handles) instead of raw pointers what in my opinion adds complexity but not safety,

Sara

evilrix 2015-05-15 at 11:04:22ID: 40778750

What complexity do you see? Assuming there is heap allocations to clean up isn't adding extra code to deal with that plus the possibility of exceptions far more complex than just making use of the RAII design pattern? What you perceive as complexity I (and many well respected authorities in C++)  see as good practice.

Again, I am pains to point out I am only arguing for the general case and grant there will always be exceptions. Maybe your example is such an exception, that really depends on the use case.

Still, don't take my word for it, consider the collective wisdom of some of the leading authorities in C++:

https://isocpp.org/wiki/faq/containers#container-of-smart-ptr

- Bjarne Stroustrup, Herb Sutter, Andrei Alexandrescu

Also interesting:

http://www.drdobbs.com/collecting-shared-objects/184401839

sarabande 2015-05-15 at 11:50:11ID: 40778805

it probably is not the right thread to discuss this but as the Asker has abandoned the thread anyhow ...

do you use smart pointers yourself? i don't. and i didn't beside of a time as teacher where smart pointers were part of the curriculum. nevertheless i have seen a lot of projects where they used smart pointers and none of them actually has used them rightly. either they were unnecessary (as in the case here where i know exactly how many copies of the pointer i need and why) or they were used in a multi-threaded context where they don't add thread-safety (as we both know from an other thread)  or there were still copies of the raw pointer used somewhere what obviously makes the smart pointer useless or even more dangerous. the reasons why these flaws were done not always was inability but sometimes due to the complexity of the configuration. if you need to pass information between shared libraries (.so) or dynamic link libraries (.dll), you can't pass smart pointers. even within one project it may be difficult or impossible to change all existing interfaces from raw pointers to smart pointers. if you then be aware that the majority of all pointers used were simple pointers to char, you probably agree that it would make much more sense to changing those to std::string than to using smart pointers.

the additional complexity a smart pointer adds is not that it couldn't be created easily (though even this hurdle might prevent many from usage) but that you consequently have to use the smart pointer instead of the raw pointer. this is easy if you have only one function (but then it is not really needed) and it might be impossible if you have to pass the pointer to other functions even if you were responsible for the interfaces yourself.

Sara

sarabande 2015-05-15 at 12:03:20ID: 40778825

- Bjarne Stroustrup

sorry, i didn't find Bjarne Stroustrup at the link? Actually, Stroustrup was a C programmer (and loved raw pointers because of this). i read many books of him but can't remember one where he recommended the usage of smart pointers. he also supported to learn C before C++ (and practiced it in his books) what probably makes him not a good advocate for pure OOP with c++.

Note: forget that std::auto_ptr ever existed. Really. You don’t want to use it, ever, especially in containers. It is broken in too many ways.

do you agree that those kind of statements are NOT helpful tp propagate the usage of smart pointers?

the properties are in the general page of 'configuration properties' and not of 'C/C++'.

the case also probably is that you have to turn your settings from UNICODE to Multi-Byte Character set (and not reverse) since the vs2003 probably used ansi character set while younger versions of visual studio turned the default to UNICODE.

Sara

evilrix2015-05-15 at 14:05:21ID: 40779012

>> sorry, i didn't find Bjarne Stroustrup at the link?
The whole website is a collaboration of the three, along with other authoritative writers who contribute.
https://isocpp.org/faq

>> do you agree that those kind of statements are NOT helpful tp propagate the usage of smart pointers?
No, I believe auto_ptr is evil and should never have been part of the standard. Read my article on Smart Pointers to find out why.

The auto_ptr cannot be used in STL containers, the behaviour of doing so is undefined. As far as I am concerned, it is the complete opposite of a smart pointer - it's a stupid pointer! If you are using it in STL containers it might explain why you feel there are "complexities". If you use std::shared_ptr or std::unique_ptr, you'll find the behaviour is seamless from raw pointers except one doesn't have to worry about issues of ownership, exception safety nor clean-up.

Again, just in case it wasn't clear the first two times I states it, I am ONLY referring to the general case here. In other words, unless there is a good reason not to, it is almost always better to stick with user smart pointers, especially when they are being used in STL containers.

That said, I do accept your premise that sometimes there is a good reason not to use them: memory constraints, performance constraints or maybe you've implemented your own heap manager using placement new. For most cases, however, using smart pointers is the right thing to do. Remember the saying, "premature optimization is the root of all evil"?

Sadly, until C++11 this wasn't so straight forward because the language didn't really have its own and so you were stuck with using Boost or rolling your own. Since C++11 there really is no good reason to not use smart pointers to ensure your code is robust (unless there is a valid reason not to).

If you don't want to use smart pointers that's fine, but to overlook their benefit just because they don't seem to fit with your world view is slightly dismissive of evidence, IMHO. You seem to suggest they add complexity, I have no idea what you mean by that, but not using them certainly does. You leave your code open to a number of issues for which you'll then have to implement additional code to workaround. Why, C++ already provides you the solution in the form of the RAII pattern??

I've pretty much said everything I have to say on this and I'm pretty sure any sensible minded software engineer will judge for themselves (one way or the other). You may continue to post objections to this but I'll let others be the final judge.

At this point I am just waiting for Paul to make a recommendation for closure before I finalise it for "clean-up".

sarabande2015-05-15 at 15:47:28ID: 40779206

I have no idea what you mean by that

oh. you never seen an interface that's wants a raw pointer and where you have troubles to feed it with a smart pointer? what advice do you give when a void pointer has to be passed for use in a callback?

actually i submitted not an objection but hoped that the general case you claim for, not necessarily may be crucial for your valuation of the question here. you know better than me that smart pointers don't play a major rule at ee from side of the askers. you may lead that back to a form of viewing the world in a 'slightly dismissive of evidence' but perhaps it is only a sense for realities and the little benefits smart pointers provide granted you were experienced enough to avoid pointers anyhow where it is possible and have a valid concept how to avoid memory leaks without being patronized by an concept that similar to exception handling for error purposes only has the purpose to repair conceptional mistakes you made before. as such a mistake i see the usage of copies of pointers to objects what in my opinion was encouraged by the usage of smart pointers.

No, I believe auto_ptr is evil and should never have been part of the standard.

you didn't get the point, probably. the standard is not an holy cow but was made by people who make mistakes like that with auto_ptr. nevertheless a standard may be discredited by those kind of mistakes and stating that these things had been bad and the new thing is good but not explaining why it could have happened in the first case and what have be done to avoid the issues in the second case, necessarily must let arise doubts whether the lessons really have be learned.

Sara