2

There have been tons of questions asked about passing by reference or pointer, and when to use pointers.

My understanding of the subject so far is the following rules:

  • Always try to pass by reference
  • Pass by pointer (only use pointers) if you must

In my case, I must use pointers in order to retain polymorphic behaviours as I am storing the passed object into a vector for later use (it is an 'add' method).
See: C++ Overridden method not getting called

I have read:

So my question is this:
If I am trying to pass a pointer already contained in a shared_ptr to add to a vector, should I

  • pass a reference to the shared_ptr to be added into the vector (because the other method is unwieldy)

or

  • use shared_ptr::get to get the actual pointer, pass that pointer, re-wrap it using shared_ptr::reset, and then add it to the vector? (because I should only pass smart pointers if I'm transferring ownership)

Code:

//method definition void addToVector(shared_ptr<Object>& obj) { myVector.push_back(obj); } //call shared_ptr<Object> myObj = make_shared<Object>(); addToVector(myObj); 

or

//method definition void addToVector(Object* obj) { shared_ptr<Object> toAdd; toAdd.reset(obj); myVector.push_back(toAdd); } //call shared_ptr<Object> myObj = make_shared<Object>(); addToVector(myObj.get()); 
14
  • It depends, you need to give us the lifetime of the pointed to object. Commented Jul 17, 2016 at 21:48
  • 1
    A "rule" that says "Always try to pass by reference" is not a rule I would like to follow. Passing native data types (like int or double) by reference doesn't make sense unless the function is supposed to modify the value. Commented Jul 17, 2016 at 21:49
  • @RichardCritten the pointed to object will last until the program ends Commented Jul 17, 2016 at 21:50
  • 3
    Regarding your last example, that's actually bad and will lead to undefined behavior. You suddenly have two distinct std::shared_ptr object wrapping the same pointer, without any knowledge of each other. If the reference-counter on one goes to zero the memory is deleted, but the other shared pointer object will still have a pointer to the (now deleted) object. Commented Jul 17, 2016 at 21:51
  • 2
    @Yidna: wouldn't make any difference. You've said, the object lasts until end of program. If this is true then it remains true regardless of whether the object is referred to by the vector or not. So there's no point using shared_ptr for it, since the whole purpose of shared_ptr is to manage object lifetime and in effect you've said that these objects don't need their lifetimes managed. Commented Jul 17, 2016 at 21:57

2 Answers 2

2

I must use pointers in order to retain polymorphic behaviours as I am storing the passed object into a vector for later use

If you store the pointed object in vector, then you don't retain polymorphic behaviours.

Should I ... use shared_ptr::get to get the actual pointer, pass that pointer, re-wrap it using shared_ptr::reset, and then add it to the vector?

No. A shared pointer may not take ownership of the pointer that is already owned by another shared pointer. This would have undefined behaviour.

(because I should only pass smart pointers if I'm transferring ownership)

If you intend to store a shared pointer to the object, then you are transferring (sharing) the ownership. If that is your intention, then pass a const reference to the shared pointer, as described in the linked answer.

If you don't intend to share the ownership, then storing a shared pointer is not what you should do. You may want to store a reference wrapper, bare pointer, or a weak pointer instead. How you should pass the reference to the function, will depend on what you choose to do with it.

Sign up to request clarification or add additional context in comments.

5 Comments

Edited my original question to 'storing' instead of 'adding' to better reflect my intentions.
@Yidna wasn't it 'copying' instead? Anyway, I changed the answer to reflect that.
Yes, it used to say "as I am copying the passed object", but that didn't accurately reflect what I meant to say so I changed it to "storing the passed object" as this allows for ambiguity as to whether a value is copied, a reference is copied, or a pointer is copied.
I will accept this answer, but I will add that I ended up using weak_ptr as recommended by @JoachimPileborg
@Yidna I expanded the answer slightly, to include the mention of weak pointers as well.
0

The second example is undefined behavior, so cannot be considered as a valid approach at all:

void addToVector(Object* obj) { shared_ptr<Object> toAdd; toAdd.reset(obj); // n.b. could just use shared_ptr(obj) ctor myVector.push_back(toAdd); } shared_ptr<Object> myObj = make_shared<Object>(); addToVector(myObj.get()); // UB 

What happens is that myObj owns its referent, then you use get() to form a raw pointer to that referent, then you create a new shared_ptr with the same referent in addToVector(). Now you have two smart pointers which refer to the same object but the two smart pointers don't know about each other, so will each destroy the object, which is double-free, which is undefined behavior.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.