dramadwarfie
dramadwarfie

Reputation: 25

Should I be using unique_ptr if I'm not trying to manage the memory of the object I'm pointing at?

I have three classes: A, B, C

in class A there is a vector<vector<B>>

in class C there is a vector<unique_ptr<B>> the ptrs in the C vector simply points at the elements of the 2d vector in class A.

I only want a reference to these elements and I don't want to have to create new memory with these pointers (not sure if that is what the unique_ptrs are doing).

In this case, would I be better off just using raw pointers?

EDIT: I don't want the objects I'm pointing at to be deleted when the vector is deleted (when the ptrs go out of scope)

Upvotes: 0

Views: 328

Answers (2)

Nikos C.
Nikos C.

Reputation: 51920

The lifetime if the B objects is managed by the vector in A. That means there is no need to wrap a unique_ptr around them. In fact, that's an error if your unique_ptrs are not created using a no-op deleter; in that case, they will delete the objects, and then the vector will delete them again.

Since C just needs to observe the objects, you can use raw pointers. Non-owning raw pointers (meaning pointers you never call delete on) are fine.

However, this kind of long-term raw pointer can be hard to reason about. Are the objects pointed to still valid? How do you know? You might want to instead add an API to A that provides access to the objects and only access them in C when needed, without storing any pointers to them.

Upvotes: 0

ShadowRanger
ShadowRanger

Reputation: 155674

You can't (well, shouldn't unless you love corrupting all the things) use unique_ptr to refer to objects not allocated via new (or implicitly via std::make_unique).

Using raw pointers isn't a particularly good idea either unless you fully initialize A's 2D vector before initializing C's, and then never resize it after that; resizing would invalidate your pointers, causing undefined behavior should you attempt to read from them.

I'd recommend 1 of 2 options, depending on what works best in your scenario:

  1. Use a vector<vector<std::shared_ptr<B>>> in A (populating it with types allocated via std::make_shared) and make C's vector either vector<std::shared_ptr<B>> (if deleting from A should not affect C and there aren't reference cycles involved) or vector<std::weak_ptr<B>> (if deleting from A should remove the reference in C)

  2. If C points to a logical index in A (where changing the value in A's vector should change what is seen through C), change C to hold:

    a. A reference to A's vector (or A itself)

    b. A vector<std::pair<size_t, size_t>> where each pair defines the indices to use to look up the associated value in A's vector.

Option 2 means A doesn't have to change much, if at all (aside from making sure C can see its vector); the vector remains value based, so using a value in it remains only two random access indirections, not the 3-4 required when using shared_ptr (std::make_shared means it's effectively 3, where manually calling new and std::shared_ptr is 4).

Upvotes: 1

Related Questions