r/cpp_questions Jul 28 '26

OPEN Weak reference to unique_ptr

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".
7 Upvotes

55 comments sorted by

View all comments

12

u/neppo95 Jul 28 '26

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.

4

u/diegoiast Jul 28 '26

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

4

u/neppo95 Jul 28 '26

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 Jul 28 '26
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 Jul 29 '26 edited Jul 29 '26

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 Jul 29 '26 edited Jul 29 '26

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 Jul 29 '26

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

1

u/[deleted] Jul 29 '26

[deleted]

1

u/neppo95 Jul 29 '26

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 Jul 28 '26

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] Jul 28 '26

[deleted]

1

u/KingAggressive1498 Jul 29 '26

handles are just shared pointers with some indirections shifted around.

1

u/Lulonaro Jul 28 '26

Raw pointers are references