Accelerated C++: Can I substitute raw pointers for smart pointers? - c++

I love this book, sadly it does not cover smart pointers as they were not part of the standard back then. So when reading the book can I fairly substitute every mentioned pointer by a smart pointer, respectively reference?

"Smart Pointer" is a bit of a misnomer. The "smart" part is that they will do some things for you, whether or not you need, want, or even understand what those things are. And that's really important. Because sometimes you'll want to go to the store, and smart pointers will drive you to church. Smart pointers solve some very specific problems. Many would argue that if you think you need smart pointers, then you're probably solving the wrong problem. I personally try not to take sides. Instead, I use a toolbox metaphor - you need to really understand the problem you're solving, and the tools that you have at your disposal. Only then can you remotely expect to select the right tool for the job. Best of luck, and keep questioning!

Well, there are different kinds of smart pointers. For example:
You could create a scoped_ptr class, which would be useful when you're allocating for a task within a block of code, and you want the resource to be freed automatically when it runs of of scope.
Something like:
template <typename T>
class scoped_ptr
{
public:
scoped_ptr(T* p = 0) : mPtr(p) {}
~scoped_ptr() { delete mPtr; }
//...
};
Additionally you could create a shared_ptr who acts the same but keeps a ref count. Once the ref count reach 0 you deallocate.
shared_ptr would be useful for pointers stored in STL containers and the like.
So yes, you could use smart pointers for most of the purposes of your program.
But think judiciously about what kind of smart pointer you need and why.
Do not simply "find and replace" all the pointers you come across.

No.
Pointers which represent object ownership should be replaced by smart pointers.
Other pointers should be replaced by iterators (which in the simplest case is just a typedef for a raw pointer, but no one would think they need to delete).
And of course, the implementation code for smart pointers and iterators will continue to need raw pointers.

Related

C++ 11 Smart Pointer usage

I have a question about smart pointers in c++ 11. I've started to have a look at C++ 11 (I usualy program in c#) and read some thing about smart pointers. Now i have the question, does smart pointers completely replace the "old" style of pointers, should i always use them?
The unique_ptr seems to solve all problems with memory management in C++, or am i wrong?
For example:
std::unique_ptr<GameManager> game (new GameManager());
game->Start();
Seems to be much smarter than:
auto *game2 = new GameManager();
game2->Start();
delete game2;
Thank you, i am a little bit confused!
For the usage shown, while the unique_ptr is better than a raw pointer as it indicates ownership of the allocated resources, you probably shouldn't use any kind of pointer at all. Instead just declare a local:
GameManager game;
game.Start();
This may not suffice if the ownership may have to be given to something else, whereas the ownership of a unique_ptr can easily be transferred.
To answer your question: yes, they do solve memory management problems.
It is considered good style to use them as much as possible.
They eliminate many possible programming errors, and reduce the difficulty of creating correct code with pointers.
To go even further, it is considered good to change
std::unique_ptr<GameManager> game (new GameManager());
To:
std::unique_ptr<GameManager> game (std::make_unique<GameManager>());
No, don't completely replace all raw pointers.
Using smart pointers (unique_ptr, shared_ptr) is only really useful for those pointers that own and manage the memory of the pointer. However, if a function takes a pointer as a parameter, then you don't want to transfer ownership. The function just needs to access the pointer.
void ShowCredits(GameManager* game) // Just use game, don't take ownership.
{ // A raw pointer here is good.
// ...
}
void main()
{
auto game = make_unique<GameManager>(); // game owns the GameManager.
game->Start();
ShowCredits(game.get());
}
P.S. If ShowCredits relies on game always being valid (i.e. it can't optionally have a value of nullptr), you may actually be better off in this case with the parameter being of type GameManager&.
In addition to the single ownership of unique_ptr, there are also situations where there is shared, or difficult to define ownership. In those cases, shared_ptr provides reference counting and the last owner will delete the referent.
In the cases where shared_ptr might be involved in a complex reference loop, the standard also provides weak_ptr.
All of these take the place of the older auto_ptr.

Implementing Containers using Smart Pointers

Ok, so everyone knows that raw pointers should be avoided like the plague and to prefer smart pointers, but does this advice apply when implementing a container? This is what I am trying to accomplish:
template<typename T> class AVLTreeNode {
public:
T data;
unique_ptr<AVLTreeNode<T>> left, right;
int height;
}
Unique_ptr can make container functions more cumbersome to write because I can't have multiple raw pointers temporarily pointing to the same object in a way that is elegant. For example:
unique_ptr<AVLTreeNode<T>> rotate_right(unique_ptr<AVLTreeNode<T>> n1)
{
unique_ptr<AVLTreeNode<T>> n2 = n1->left;
n1->left = n2->right;
n2->right = n1;
// n1 must now be referenced through the longer name n2->right from now on
n2->right->recalculate_height();
n2->recalculate_height();
return n2;
}
(It's not a big deal in this example but I can imagine how it could become a problem). Should I take problems like these as a strong hint that containers should be implemented with good old new, delete, and raw pointers? It seems like awfully a lot of trouble just to avoid writing a destructor.
I do not usually use smart pointers when implementing containers as you show. Raw pointers (imho) are not to be avoided like the plague. Use a smart pointer when you want to enforce memory ownership. But typically in a container, the container owns the memory pointed to by the pointers making up the data structure.
If in your design, an AVLTreeNode uniquely owns its left and right children and you want to express that with unique_ptr, that's fine. But if you would prefer that AVLTree owns all AVLTreeNodes, and does so with raw pointers, that is just as valid (and is the way I usually code it).
Trust me, I'm not anti-smart-pointer. I am the one who invented unique_ptr. But unique_ptr is just another tool in the tool box. Having good smart pointers in the tool box is not a cure-all, and using them blindly for everything is not a substitute for careful design.
Update to respond to comment (comment box was too small):
I use raw pointers a lot (which are rarely owning). A good sampling of my coding style exists in the open source project libc++. One can browse the source under the "Browse SVN" link.
I prefer that every allocation of a resource be deallocate-able in a destructor somewhere, because of exception safety concerns, even if the usual deallocation happens outside of a destructor. When the allocation is owned by a single pointer, a smart pointer is typically the most convenient tool in the tool box. When the allocation is owned by something larger than a pointer (e.g. a container, or a class Employee), raw pointers are often a convenient part of the data structure composing the larger object.
The most important thing is that I never allocate any resource without knowing what object owns that resource, be it smart pointer, container, or whatever.
The code you presented compiles with no problems
#include <memory>
template<typename T> class AVLTreeNode {
public:
T data;
std::unique_ptr<AVLTreeNode<T>> left, right;
int height;
};
int main()
{
AVLTreeNode<int> node;
}
test compilation: https://ideone.com/aUAHs
Personally, I've been using smart pointers for trees even when the only thing we had was std::auto_ptr
As for rotate_right, it could be implemented with a couple calls to unique_ptr::swap
Small correction: raw pointers should not be avoided like the plague (oops, not everybody knew the fact), but manual memory management should be avoided when possible (by using containers instead of dynamic array or smartpointers), so in your function, just do a get() on your unique_ptr for temporary storage.
std::shared_ptr does not have these restrictions. Especially, multiple shared_ptr-instances can reference the same object.
Herb Shutter has very clear guideline about not using shared_ptr as parameters in his GoTW series:
Guideline: Don’t pass a smart pointer as a function parameter unless
you want to use or manipulate the smart pointer itself, such as to
share or transfer ownership.
and this...
Guideline: Prefer passing objects by value, *, or &, not by smart
pointer.

Should I use smart pointers on everything and forget about classic normal pointers?

I've been using C++ for a long time and know very well about carefulness in allocating and deallocating memory, especially not forgetting to delete unused instances.
Now, I've just recently used boost and with a problem I am facing I'm forced to used smart pointers (specifically the shared_ptr) one. So, if I am going to use shared_ptr for this problem, should I use smart pointers to all my normal pointer codebase?
You should use smart pointers careful. They are not the silver bullet when considering memory management. Circular references are still an issue.
When making the class design, always think who has the ownership of an object (has the responsibility to destroy that object). Complement that with smart pointers, if necessary, but don't forget about the ownership.
Yes, you should greatly prefer smart pointers over bare pointers for almost everything. But that does not mean you should be using ::boost::shared_ptr for most of those cases. In fact I think you should use shared_ptr sparingly and carefully.
But for those pointers you don't use shared_ptr for you should be using ::std::auto_ptr or, if you have C++0x ::std::unique_ptr. And if they aren't appropriate, you should find a smart pointer type that is.
Now this isn't always the right answer, just almost always. Smart pointers are invaluable for tracking and freeing memory resources appropriately even in the face of exceptions or other such oddities of control flow.
There are cases in which you will need to either write your own smart pointer class or not use one. These cases are very rare, but they exist.
For example, using a smart pointer in your own smart pointer class is probably not the right thing to be doing. Pointing at stuff allocated in a C library would probable require a custom smart pointer that called free instead of delete. Maybe you want a stretchy buffer you can call realloc on and don't want to use a ::std::vector for some reason.
But generally, a smart pointer (though not usually ::boost::shared_ptr (or in C++0x ::std::shared_ptr)) is the right answer to your resource management problem.
Yes. You should be using the Boost smart pointers for most everything if you have them available. Remember this, while you can and from your comments do use pointers effectively, the person/people that come after you may not. Using the smart pointers can and will (hopefully, can't guard against bad code) mitigate some of these issues.
I'd also recommend using scoped_ptr inside your classes even if your classes are designed well. It'll help guard against issues the next guy could/might/most likely will introduce when faced with a naked pointer. It'll encourage them to use them too, by example. The last thing you want is to have to track down a memory issue because someone forgot to initialize the pointer to NULL and it's passing the if statement check.
No, you should not use smart pointers for everything.
What you should consider whenever typing new:
What is the lifetime of this object?
Which object owns it?
How is that object going to manage its lifetime?
Sometimes the solution is a smart pointer but also the lazy answer. "I don't want to be bothered to work out which object owns this pointer and what its lifetime should be hence I'll make it a shared_pointer!"
The important question is; What is managing the lifetime of this object?, the answer can be a smart pointer, but oftentimes, it doesn't need to be.
No. It depends on what you're doing.
Smart pointers have a performance overhead. In desktop applications, this is typically not a concern, but depending on what you do, it might be.
Smart pointers will not work right if you have reference cycles, i.e. A pointing to B and B pointing to A, or even something pointing to itself.

Smart pointers - cases where they cannot replace raw pointers

HI,
I have this query about smart pointers.
I heard from one of my friends that smart pointers can almost always replace raw pointers.
but when i asked him what are the other cases where smart pointers cannot replace the raw pointers,i did not get the answer from him.
could anybody please tell me when and where they cannot replace raw pointers?
Passing pointers to legacy APIs.
Back-references in a reference-counted tree structure (or any cyclic situation, for that matter). This one is debatable, since you could use weak-refs.
Iterating over an array.
There are also many cases where you could use smart pointers but may not want to, e.g.:
Some small programs are designed to leak everything, because it just isn't worth the added complexity of figuring out how to clean up after yourself.
Fine-grained batch algorithms such as parsers might allocate from a pre-allocated memory pool, and then just blow away the whole pool on completion. Having smart pointers into such a pool is usually pointless.
An API that is going to be called from C, would be an obvious example.
Depends on the smart pointer you use. std::auto_ptr is not compatible with STL containers.
It's a matter of semantics:
smart pointer: you own (at least partly) the memory being pointed to, and as such are responsible for releasing it
regular pointer: you are being given a handle to an object... or not (NULL)
For example:
class FooContainer
{
public:
typedef std::vector<Foo> foos_t;
foos_t::const_iterator fooById(int id) const; // natural right ?
};
But you expose some implementation detail here, you could perfectly create your own iterator class... but iterator usually means incrementable etc... or use a pointer
class FooContainer
{
public:
const Foo* fooById(int id) const;
};
Possibly it will return NULL, which indicates a failure, or it will return a pointer to an object, for which you don't have to handle the memory.
Of course, you could also use a weak_ptr here (you get the expired method), however that would require using shared_ptr in the first place and you might not use them in your implementation.
interaction with legacy code. if the api needs a raw pointer you need to provide a raw pointer even if once its in your code you wrap it in a smart pointer.
If you have a situation where a raw pointer is cast to an intptr_t and back for some reason, it cannot be replaced by a smart pointer because the casting operation would lose any reference counting information contained in the smart pointer.
It would be quite hard to implement smart pointers if at some point you don't use plain pointers.
I suppose it would also be harder to implement certain data structures with smart pointers. E.g freeing the memory of a regular linked list is quite trivial, but it would take some thought to figure out the combination of owning and non-owning smart pointers to get the same result.

Once you've adopted boost's smart pointers, is there any case where you use raw pointers?

I'm curious as I begin to adopt more of the boost idioms and what appears to be best practices I wonder at what point does my c++ even remotely look like the c++ of yesteryear, often found in typical examples and in the minds of those who've not been introduced to "Modern C++"?
I don't use shared_ptr almost at all, because I avoid shared ownership in general. Therefore, I use something like boost::scoped_ptr to "own" an object, but all other references to it will be raw pointers. Example:
boost::scoped_ptr<SomeType> my_object(new SomeType);
some_function(my_object.get());
But some_function will deal with a raw pointer:
void some_function(SomeType* some_obj)
{
assert (some_obj);
some_obj->whatever();
}
Just a few off the top of my head:
Navigating around in memory-mapped files.
Windows API calls where you have to over-allocate (like a LPBITMAPINFOHEADER).
Any code where you're munging around in arbitrary memory (VirtualQuery() and the like).
Just about any time you're using reinterpret_cast<> on a pointer.
Any time you use placement-new.
The common thread here is "any situation in which you need to treat a piece of memory as something other than a resource over which you have allocation control".
These days I've pretty much abandoned all use of raw pointers. I've even started looking through our code base for places where raw pointers were used and switched them to a smart pointer variant. It's amazing how much code I've been able to delete by doing this simple act. There is so much code wasted on lifetime management of raw C++ pointers.
The only places where I don't use pointers is for a couple of interop scenarios with other code bases I don't have control over.
I find the primary difference between 'modern' C++ and the old* stuff is careful use of class invariants and encapsulation. Well organised code tends naturally to have fewer pointers flying around. I'm almost as nervous swimming in shared_ptrs as I would be in news and deletes.
I'm looking forward to unique_ptr in C++0x. I think that will tidy away the few (smart) pointers that do still roam the wild.
*still unfortunately very common
Certainly any time you're dealing with a legacy library or API you'll need to pass a raw pointer, although you'll probably just extract it from your smart pointer temporarily.
In fact it is always safe to pass a raw pointer to a function, as long as the function does not try to keep a copy of the pointer in a global or member variable, or try to delete it. With these restrictions in place, the function cannot affect the lifetime of the object, and the only reason for a smart pointer is to manage the object lifetime.
I still use regular pointers in resource-sensitive code or other code that needs tiny footprint, such as certain exceptions, where I cannot assume that any data is valid and must also assume that I am running out of memory too.
Managed memory is almost always superior to raw otherwise, because it means that you don't have to deal with deleting it at the right place, but still have great control over the construction and destruction points of your pointers.
Oh, and there's one other place to use raw pointers:
boost::shared_ptr<int> ptr(new int);
I still use raw pointers on devices that have memory mapped IO, such as embedded systems, where having a smart pointer doesn't really make sense because you will never need or be able to delete it.
If you have circular data structures, e.g., A points to B and B points back to A, you can't use naively use smart pointers for both A and B, since then the objects will only be freed extra work. To free the memory, you have to manually clear the smart pointers, which is about as bad as the delete the smart pointers get rid of.
You might thing this doesn't happen very often, but suppose you have Parent object that has smart pointers to a bunch of Child objects. Somewhere along the way someone needs to look up a the Parent for a Child, so they add a smart pointer member to Child that points back to the parent. Silently, memory is no longer freed.
Some care is required. Smart pointers are not equivalent to garbage collection.
I'm writing C++ that has to co-exist with Objective C (using Objective C++ to bridge).
Because C++ objects declared as part of Objective C++ classes don't have constructors or destructors called you can't really hold them there in smart pointers.
So I tend to use raw pointers, although often with boost::intrustive_ptr and an internal ref count.
Not that I would do it, but you need raw pointers to implement, say, a linked list or a graph. But it would be much smarter to use std::list<> or boost::graph<>.