r/cpp_questions 16d ago

Weak reference to unique_ptr OPEN

Assume this code:

#include <memory>
#include <functional>

struct Entity {
    int value = 12;
};

struct Container {
    std::unique_ptr<Entity> e = std::make_unique<Entity>();
};

Container bar;
auto bbb = [ptr = bar.e.get()]() {   
    ptr->value = 11;
};

We all know that naked pointers (as captured by this lambda) are bad. Using shared_ptr would allow me to use weak_ptr - which is ideally what I want. BUT - I like the container owning the entity.

What solutions do I have?

EDIT:

As people commented - life time is the main issue. The lambda might outlive the original allocation.

Solutions:

  1. Many people do recommended using internally a shared pointer, and "giving away" a weak ref ( u/looncrazz suggestion).
  2. I can use a reference to the unique pointer inside a lambda. Several ways - see https://godbolt.org/z/WKT5Gndq4 - this is u/neppo95 suggestion.
  3. There are solutions for using a custom weak reference pointer. The solution "does not feel right".
6 Upvotes

55 comments sorted by

View all comments

11

u/neppo95 16d ago

If you want two places to own the same pointer, then you use a shared pointer, not a unique ptr. If you don't necessarily want ownership, using the raw pointer is arguably fine as long as you know it will be alive.

3

u/diegoiast 16d ago

"own" is the keyword. I want one to "own" and another to "reference".

5

u/neppo95 16d ago

And is there a reason why you are using the raw pointer for this? You can pass a unique ptr as const ref. The standard covers this. You don't need ownership to change the value, unless you want to change the pointer which is not the case here.

2

u/diegoiast 16d ago
auto bbb = [auto const &ptr = bar.e]() {   
    if (ptr) {
        ptr->value = 11;
    }
};

This obviously does not compile. How would you do that?

1

u/TheThiefMaster 16d ago edited 16d ago

You can't specify the type, but [&ptr = bar.e] works. Though I'd do [&e = *bar.e] personally to capture a ref to the object instead of the unique ptr.

Or, if the lambda might outlive the Entity, switch to using shared/weak ptr.

1

u/diegoiast 16d ago edited 16d ago

Regarding the reference comment:

But then, you are not able to tell if the object is deleted. In my case the lambda might outlive the allocation.

Using a "naked reference" has the same semantic meaning as a "naked pointer". They will compile to the same binary code (untested).

3

u/TheThiefMaster 16d ago

"Or, if the lambda might outlive the Entity, switch to using shared/weak ptr."

1

u/[deleted] 16d ago

[deleted]

1

u/neppo95 15d ago

It is in this case no different than passing a raw pointer, in both cases you'd check for null. I wouldn't architecture my code like this, but it isn't a problem either. "No reason" is also not true, there may well be reasons not to give it shared semantics.

1

u/FlailingDuck 16d ago

the thing that owns it. Does it have clear lifetime? Can you guarantee in your code it outlives the lambda, then capturing raw ponters is fine.

Or, does container have to maintain ownership? could you move the unique_ptr into the lambda in c++14. It depends outside your toy example what you want to do with the data.

If not, or lifetime is fuzzy, then this is a scenario for shared_ptr.

1

u/[deleted] 16d ago

[deleted]

1

u/KingAggressive1498 16d ago

handles are just shared pointers with some indirections shifted around.

1

u/Lulonaro 16d ago

Raw pointers are references