[C++] How to take my pointer game to the next level?

So I’ve got my basic pointer wisdom down… Pointers of different types, void/raw pointers (actually, I haven’t got this one down, but let’s ignore for now), pointers to parent classes that can then be used to point to polymorphic child classes, new/delete operators, pointer assignment, etc.

But I’ve been avoiding a frightful topic for too long now, and I can’t avoid it anymore, because I’m running into trouble with the concept of ownership.

And that is std::unique_ptr, std::shared_ptr, in JUCE i’ve seen ScopedPointer - all this kind of stuff (I think, all under the umbrella term ‘smart pointers’) - and I think ‘ownership’ has to do with that.

So is there a book, a lecture, some resource I can consume to better understand it all?

Please no cppreference.com links… That’s for C++ in god mode.

Have no fear, that’s your best friend.

Basically all “smart pointers” have a pointer to a type (that’s why they are templated, like std::unique_ptr<Foo>, and additional information, if that object is still needed.

std::unique_ptr owns one object. The trick is to use the unique_ptr on the stack, and use the natural way, when the scope is finished. The unique_ptr will then automatically delete the object it points to. So you cannot forget to delete an instance and leak it.

std::shared_ptr is the same like ReferenceCountedObject. Each object in a shared_ptr has also a reference count, so it knows, how many shared_ptrs are interested in that object. Once the last shared_ptr to an object goes out of scope, the pointed to object is deleted, again, no delete call necessary.

They work best together with auto, since that will always use the right type and saves typing.

And to create the pointers, there is often a factory. To create a unique_ptr, you call std::make_unique<Foo>(constructorArg1, constructorArg2, ...), to create a shared_ptr you call std::make_shared<Foo>(constructorArg1, constructorArg2, ...).

And they overload the operator*(), so you can use them with the normal dereferencing and using ->, while the methods with . call the methods of the pointer itself, like get() to retrieve a raw pointer, release() to end management (and leak it eventually).

1 Like

cppreference doesn’t IMHO usually really explain why or when to use something, though. Like the name says, the site is just a reference of what is available in the language and standard library. It’s still better than the C++ standard document itself, though… :wink:

1 Like

You are right, it’s a reference, not a learning site. Still I find the examples often helpful, even though some of them are a bit bloated, because they want to show many use cases in one example, like https://en.cppreference.com/w/cpp/memory/unique_ptr#Example

Splitting this in a trivial and the more advanced usage would be beneficial, but at least it’s complete… that’s better than a learning site, that covers only half the API…

Apart from all that I highly encourage you to use references as much as possible - it’s the safe way and it performs the same :wink:

Oh yeah, I am definitely pointer-shy, so I avoid at all costs, then go to references, then occasionally you may see me use a new operator. But beyond that, never.

Is there a good book to get on the subject? A bit like Concurrency in Action for threading, but then a book just about smart pointers?

I would avoid

new

at all except when using smart pointers. Why do you need a book? There are hundreds of tutorials about this and also right in this thread @daniel explained it very good!

2 Likes

Besides, you can learn half of C without knowing what a pointer is :slight_smile:

1 Like

Right, okay, it’s just that I recently realised there’s a whole book dedicated to std:thread so I thought hell there’s at least a book’s worth on pointers.

I do want to watch a video tutorial of some of this in action though, any particular keywords to search for, or just “smart pointers” encapsulates all of this?

I found this lecture on memory management which I’m planning to watch, and looks great: https://www.youtube.com/watch?v=mMpBw7S2cqw

Why is new a bad idea? Just because then the responsibility becomes yours?

New returns a raw pointer. The problem with raw pointers is, that there is no information about ownership and lifetime. You need to transport this information to the user by adding a comment, like you sometimes read in the docs: “it is the callers responsibility to delete this after use”.

The whole smart pointer thing is about making this information implicit rather than explicit as comment or variable names.

Technically there is nothing wrong with creating an object and putting it into a smart pointer, so this works as well:

std::unique_ptr<Foo> foo { new Foo(); };
// or change it later:
foo.reset (new Foo());

But to have the full benefit of smart pointers, you want to avoid even the chance to do something accidentally wrong.
And if you migrate a codebase, you can simply do a full text search for “new” and “delete”, so you will know, where the smelly bits are.

Another benefit, since the factory returns a smart pointer, and if you use auto, then you don’t have to repeat the type:

std::unique_ptr<Foo> foo { new Foo(); }
// becomes:
auto foo = std::make_unique<Foo>();

Once the foo is on a stack, you don’t have to think about any lifetime issues any longer (as long as you are in one thread :wink: )

if you start having a relatively good grasp of other language features i can recommend “Effective Modern C++” by scott meyers. the introduction to smart pointers is pretty good.

2 Likes

That seems like the perfect book for me. Thank you!