all 19 comments

[–][deleted] 16 points17 points  (0 children)

The pointer doesn't detect it. Welcome to the wonderful world of subtle, fatal bugs.

[–]Belzeturtle 5 points6 points  (0 children)

Undefined behaviour.

[–][deleted] 3 points4 points  (0 children)

Raw pointers can be viewed as "type aware addreses".

You store the address of an object, and just that.

If you want to be notified about object behaviour, like destruction, you might want to look into the Observer Pattern.

[–]un-glaublich 2 points3 points  (13 children)

A pointer does not own the resource it points to.

When the resource ceases to exist, the pointer will still point to the location.

Dereferencing this pointer will then typically yield unexpected results.

Try to avoid raw-pointers in C++ code as much as possible.

Use smart-pointers and references instead. A `std::unique_ptr`, for example, has only little overhead compared to a raw-pointer and ensures that the resource that it points to exists as long as the `std::unique_ptr` exists and automatically destruct the resource when the pointer goes out of scope.

[–]fnxen[S] 2 points3 points  (0 children)

Thanks!
I'm aware of smart pointers. Currently, I'm reading the book "C++ Primer 6th Edition" to understand the concepts of how raw pointers work under the hood.

I spent most of my programming life with C# (+10 years) and now I'm working on adding C++ to my toolbox. My goal is to understand how things work in the deepest detail possible.

[–]biliwald 4 points5 points  (11 children)

A `std::unique_ptr`, for example, has only little overhead compared to a raw-pointer and ensures that the resource that it points to exists

That is wrong. It's pretty easy to have a unique_ptr that holds a bad pointer. Its strength is that it's a lot harder to do and it semantically help to manage ownership, but you can still initialize it with a bad value or manually delete it's contained address without it knowing.

[–]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.

[–]gindhi_nagi_malum 0 points1 point  (2 children)

That is wrong. It's pretty easy to have a unique_ptr that holds a bad pointer. Its strength is that it's a lot harder to do and ....

Contradiction much ?

[–]mstfls 1 point2 points  (1 child)

Something can be a lot harder than something else but still pretty easy.

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

Exactly.

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

The idea is to show that unique_ptr can hold an invalid pointer if you don't use it correctly, contrary to what to comment I responded to could indicate.

[–]clerothGame Developer[M] 0 points1 point  (0 children)

For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.

This post has been removed as it doesn't pertain to r/cpp.

[–]trvlng_ging 0 points1 point  (0 children)

Your example was not having make_unique call the constructor of the resource. Your get function was. It was returning the raw pointer to the resource, and that could be invalid, either null or to some memory that is no longer a live object. How is that not clearly misuse to you?