-2

I was reading about smart pointers in C++ and I am surprised that more than 99% of the given examples are in fact fairly bad examples because in those cases dynamic allocation could be avoided. I would agree to use smart pointers only in the context that STL containers wouldn't work. For instance in dynamic arrays (std::vector) performance matters so it is perhaps better to have well-tested code without any use of smart pointers.

Here what I consider a bad example because in this case unique_ptr isn't the solution, but stack allocation would be the proper way.

MyObject* ptr = new MyObject(); 
ptr->DoSomething(); 
delete ptr; 

So what could be good examples or uses for Smart Pointers in C++?

Said differently what design pattern would require to transfer the ownership of a pointer to another object?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
nowox
  • 25,978
  • 39
  • 143
  • 293
  • the premise is of course that you need to dynamically allocate something. I never saw anybody suggesting to replace automatic storage with a smart pointer managed object – 463035818_is_not_an_ai Nov 11 '20 at 09:35
  • The internet is full with examples and many SO threads as well, can you be more specific? – Tony Tannous Nov 11 '20 at 09:36
  • 3
    the question reads like a rant btw, I don't really understand what you are asking – 463035818_is_not_an_ai Nov 11 '20 at 09:36
  • for example you can find lots of questions on SO about storing polymorphic objects in containers. The correct answer is almost always to use smart pointers – 463035818_is_not_an_ai Nov 11 '20 at 09:37
  • Related: [What is move semantic?](https://stackoverflow.com/questions/3106110/what-is-move-semantics) [When to use smart pointer?](https://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one) – Tony Tannous Nov 11 '20 at 09:37
  • @TonyTannous I didn't find good use of smart pointers on Google or SO. All questions about `What is the use of smart pointers` give examples that would be better written without any use of dynamic allocation. – nowox Nov 11 '20 at 09:38
  • @idclev463035818 Just give me one single example and I will admit my question is dumb. – nowox Nov 11 '20 at 09:39
  • I just gave you one: Store polymorphic objects in a `std::vector` – 463035818_is_not_an_ai Nov 11 '20 at 09:39
  • You were already given a good example: storing polymorphic objects in containers – bolov Nov 11 '20 at 09:40
  • Another: factory pattern with polymorphic types – bolov Nov 11 '20 at 09:41
  • I am confused by some of your statements, eg " it is perhaps better to have well-tested code without any use of smart pointers." smart pointers are well tested. We had a fail with `auto_ptr` but now smart pointers are well settled in C++, suggesting that they are not well tested is a bit odd – 463035818_is_not_an_ai Nov 11 '20 at 09:42
  • Another one: storing non-moving, non-copyable objects in `std::vector` – bolov Nov 11 '20 at 09:43
  • @bolov I guess it is where I need help. Storing polymorphic objects into containers would be `vector.push_back(new Derived())`. If the object is removed from the vector, then it would be deleted. I don't see any use for smart-pointers here. – nowox Nov 11 '20 at 09:43
  • 3
    "If the object is removed from the vector, then it would be deleted" no. I suggest you to study the basics before complaining about the advanced... – 463035818_is_not_an_ai Nov 11 '20 at 09:43
  • @idclev463035818 Smart pointers are well tested, but they add overhead. So if you want to release a self-contained data container, you would certainly prefer to use regular pointers if you can make sure there is no way of memory leak. – nowox Nov 11 '20 at 09:44
  • 1
    Another one: storing objects to which you need persistent references, even when the object is moved (even when the container moves it) – bolov Nov 11 '20 at 09:44
  • 2
    dynamic memory allocation is overhead. Using a smart pointer in that case does not add overhead. No offense, but you seem to have some misconceptions – 463035818_is_not_an_ai Nov 11 '20 at 09:45
  • @idclev463035818 In my understanding keeping track of references with a count object does add some overhead. – nowox Nov 11 '20 at 09:46
  • 3
    if you do not use a smart pointer you need some other means to keep track of the lifetime of the object. That has a cost and is error prone. Smart pointers have proven to be a good solution to a common problem – 463035818_is_not_an_ai Nov 11 '20 at 09:47
  • 2
    `unique_ptr` has no overhead over `new`, and is the default smart pointer – Caleth Nov 11 '20 at 09:56
  • @idclev463035818, my bad I wanted to write `vector.push_back(Derived())` – nowox Nov 11 '20 at 09:59
  • @nowox thats even worse. Give me a second, I will try to find an example of what i was talking about above – 463035818_is_not_an_ai Nov 11 '20 at 10:01
  • there are many questions about that issue, this is a good one https://stackoverflow.com/questions/8777724/store-derived-class-objects-in-base-class-variables – 463035818_is_not_an_ai Nov 11 '20 at 10:04
  • `vector.push_back(Derived())` would result in [slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing) – Alan Birtles Nov 11 '20 at 10:32

3 Answers3

5

I am surprised that more than 99% of the given examples are in fact fairly bad examples because in those cases dynamic allocation could be avoided

This is probably because the examples are intended to be super-simple.

So what could be good examples or uses for Smart Pointers in C++?

Never mind "goodness", but consider the following examples of cases where they're relevant:

1. When you can't hold on to the stack

template <typename T>
std::unique_ptr<T[]> print_and_allocate(std::size_t n)
{
    std::cout << "Allocating " << n << " elements of size " << sizeof(T) << '\n';
    return std::make_unique<T[]>(n);
}

you can't perform the allocation on the stack, because you're returning before your allocated element is used. Also, you can't just return a single constructed or an std::array, because the number of elements to allocate is not known in advance.

2. A need to refer to one of several possible subclasses

class A;
class B : public A { /* ... */ };
class C : public A { /* ... */ };

// ...

auto my_a = std::unique_ptr<A>(condition ? (A*) new B : (A*) new C);
my_a.some_virtual_method();

3. Complex de-allocation logic

A pointer doesn't tell you when/how it needs to be freed/deallocated. You can make a simple assumption ("I need to free the pointer I get from this function"), but this already suggests expressing your assumption in a wrapper class. If the conditions for de-allocation are more complex, and especially if the pointer recipient isn't aware of them, it becomes critical that they be communicated somehow. An std::shared_ptr or std::weak_ptr are two ways to do so; and another is an std::unique_ptr with a custom deleter.

4. When future usability not guaranteed

When the provider of the pointer can't guarantee it will continue to be valid, but expects that it likely will be - you need some kind of wrapper class to reflect that fact and to make sure you don't try to dereference the pointer when you actually can't. This is where std::weak_ptr() comes into play.


More generally: If you needed to allocate memory and hold a pointer before, for some reason, and couldn't make do without it - you most-probably want to switch to using a smart pointer instead. See also:

What is a smart pointer and when should I use one (answer).

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • In your example you can return an `std::vector` and it would be automatically deleted. No need for `unique_ptr`. Am I wrong? – nowox Nov 11 '20 at 09:50
  • @nowox: No, you're not wrong. But consider my general point: If what you want is an `std::vector`, you would not have used a pointer in the first place. – einpoklum Nov 11 '20 at 09:55
  • 3
    @nowox if your class is non-copyable and non-moveable, you can't put it into vector. Also since unique_ptr doesn't have all the functionality of vector, it may have less overhead in case you don't need vector's capabilities anyway. – Aykhan Hagverdili Nov 11 '20 at 10:32
0

So what could be good examples or uses for Smart Pointers in C++?

Any situation where you need to have a ressource on the heap.

You are right that most smart pointer examples would be written with a stack allocation in a real world scenario. But they are just that - simple examples to demonstrate the use/advantages of smart pointers.

In reality however, you can't place everything on the stack. And once you need dynamic memory allocation on the heap a smart pointer is almost always a better choice than a raw pointer with new/delete.

Eric
  • 1,183
  • 6
  • 17
  • "You are right that most smart pointer examples..." this was already mentioned in the question with zero evidence and repeating it still does not convince me, just saying – 463035818_is_not_an_ai Nov 11 '20 at 10:11
  • @idclev463035818 Convince you to what? That a lot of textbook/tutorial code snippets don't show code in a real world scenario and instead use a minimal example? For example just take the cppreference entry about smart pointers: [Link](https://en.cppreference.com/book/intro/smart_pointers). This is what the op is talking about. In reality you would never use a pointer, smart or not, for an local int inside of my_func(). It is just used here to demonstrate how the use of a smart pointer can help to avoid memory leaks. – Eric Nov 11 '20 at 10:44
  • all I am saying is that OP is writing "99%", you write "most" and I don't see that. I just checked the first 7 smart pointer examples I found online. 2 of them are poor in the sense that they use a scenario where you wouldn't use dynamic allocation in the first place. 2 out of 7 is neither "most" nor 99%. 7 is of course too little statistics to make a general statement, but its more than none. Sorry I am a bit picky sometimes. I just don't see that it is most examples – 463035818_is_not_an_ai Nov 11 '20 at 10:52
  • the first example on that cppref site is btw quite poor, I agree ;) – 463035818_is_not_an_ai Nov 11 '20 at 10:54
0

In real use cases you actually don't want to care about memory management. You don't want memory leaks because you forget one delete somewhere. Thats where smart pointers come in handy, since they lift the responsibility to clean up from you.

Raildex
  • 3,406
  • 1
  • 18
  • 42
  • If I don't want to care about memory management I would probably use a high-level language, not C++. When I use C/C++ it is because I have hard constraints such as limited memory or limited CPU time. – nowox Nov 11 '20 at 11:08
  • @nowox using manual new/delete does not help you with memory limit or cpu time. `unique_ptr` is literally a zero-cost abstraction. – Aykhan Hagverdili Nov 11 '20 at 12:24
  • I partially agree for `unique_ptr` since you still have the cost of one indirection. It is worth it on most of use-cases, but can be an issue on certain embedded real-time targets. – nowox Nov 11 '20 at 12:26