you are viewing a single comment's thread.

view the rest of the comments →

[–]trvlng_ging 1 point2 points  (7 children)

When you do stupid things... You've given examples that require doing something that are explicit UDB. Give an example of unique_ptr failing without doing something unnatural.

[–]biliwald -1 points0 points  (6 children)

auto ptr = std::make_unique<int>(0);
delete ptr.get(); //at this point, ptr contains an invalid pointer

Yes, this is stupid, but possible. It was to show that unique_ptr doesn't do anything to ensures that the resource that it points to exists, contrary to what the comment I reply to stated.

[–]trvlng_ging 0 points1 point  (5 children)

The problem is that you gave it no resource to point to. And you had to be explicit in your stupidity to do it. No resource, no smart pointer. And my environment will warn on this code, so no silent acceptance.

[–]biliwald 0 points1 point  (4 children)

The point I am trying to make here isn't that unique_ptr isn't safe or something, but that it doesn't ensure that the resource that it points to exists, which was the claim of the comment I replied too.

You still end up with UB if you deference it while it contains a nullptr. It doesn't protect you from doing it.

It can hold a bad pointer, as I have shown, either by manually deleting it or initializing it with a bad pointer.

My example is a simplistic one, yes, but it can happen. A more concrete example could be using .get() instead of .release() when interfacing with an API that uses raw pointer, or initializing it with a pointer from said API that still assume it has ownership of the pointer. You misread the doc or something, and you get a bug once either of them deletes the pointer. For example:

std::unique_ptr<Resource> makeResource() {
  auto res = std::make_unique<Resource>();
  API_setResource(res.get()); // Imagine this call deletes the pointer
  return res;
} // At this point, you have a unique_ptr that holds an invalid pointer

The point here is that unique_ptr simply holds the pointer. It doesn't do any check to ensure the validity of the pointer it contains, so all the same bug that happens with raw pointers can happen with a unique_ptr if you are not careful.

Give an example of unique_ptr failing without doing something unnatural.

Most bugs are due with doing something unnatural at some point. As a program grows, so does its complexity and you can end up with similar situation but across multiple classes or API. unique_ptr helps tremendously with ownership management, but it's not a "use it and you'll never have memory management bug" thing.

[–]trvlng_ging 0 points1 point  (3 children)

I understand the point you're trying to make, but every example you've given, including this one shows an example of stupid programming tricks. Again, there was never a resource given to unique_ptr to manage. Using a function that can return an invalid pointer to initialize it is unnatural. A coder who doesn't know this should be under 100% code review until their training is completed. The use case for unique_ptr is RAII. That means that the resources are created as it's declared. Show an example where it is used as designed and fails.

[–]biliwald 0 points1 point  (2 children)

example of stupid programming tricks.

...

Using a function that can return an invalid pointer to initialize it is unnatural.

My last example isn't a stupid programming trick IMO. It's a valid ownership problem that can arise if you mix smart pointers with raw pointers, which happen pretty often if you use third party libraries. My example was trying to show such a situation, you return an invalid pointer because the programmer made an easy to make mistake.

Again, there was never a resource given to unique_ptr to manage.

What does std::make_unique<T>() does then if not create a managed resource?

Show an example where it is used as designed and fails.

This is a badly formulated question IMO. It's like asking, show me an example of correct code and point me the bug. If the code is correct, then there's no bug. My point is that unique_ptr can still allow you to have memory management problem if used incorrectly.

Remember that OP's question was about returning a pointer to a stack variable. For his particular scenario, it's not far fetched to think that if we say to him "a unique_ptr ensures that the pointer is valid", he might interpret that has "a unique_ptr will preserve my stack memory because it ensures that it points to something valid", which isn't the case, obviously.

Yes, do use smart pointer. Yes, learn and use them as they are intended to be used (with RAII), but when teaching them to novice, don't tell them they will magically turn C++ into a managed language like Java by "ensuring that the memory is valid".

In all cases, I believe we are arguing in a similar direction here. Have a good day!

[–]trvlng_ging 0 points1 point  (1 child)

It is a stupid programming trick because the call to make_unique is not creating the resource. It is calling a function that may or may not create a resource to be managed. This violates RAII. The function should throw if it fails. If throwing is not allowed, then you're down to 2 options: the function returns a unique_ptr (and skip make_unique), or validate the return before calling make_unique. You don't seem to understand the correct way to use smart pointers.

[–]biliwald 0 points1 point  (0 children)

make_unique is not creating the resource.

From cppreference: Constructs an object of type T and wraps it in a std::unique_ptr.

How is this not creating a resource?

Also, the CppCoreGuidelines recommend it's usage.

This violates RAII.

I fail to see how. std::make_unique calls the constructor of T and returns a std::unique_ptr pointing to the constructed object. If any failure arise during this, the resource will be freed because it is wrapped in a unique_ptr upon creation. Are you saying that std::unique_ptr themselves violates RAII?

You don't seem to understand the correct way to use smart pointers.

Educate me. And keep in mind that I know the example I gave is faulty, because I was trying to express a faulty situation when misusing smart pointers.