Reputation: 1501
I have a function like
void Element::setNodes(const BaseClass& input0, const BaseClass& input1)
This is called by passing a derived class.
setInputNodes(DerivedClass1, DerivedClass2)
The trouble I have is that I want to store the nodes in a vector. I have this
std::vector<std::shared_ptr<BaseClass>> m_inputNode;
and the function as
void Element::setNodes(const BaseClass& input0, const BaseClass& input1)
{
m_inputNode.push_back(input0);
m_inputNode.push_back(input1);
}
This doesn't work and I have to store it as a pointer otherwise I experience object slicing. Will I need to change the API and pass pointers? I want to change as little as possible.
Upvotes: 2
Views: 3017
Reputation: 2822
You have to take the pointers to your Elements:
void Element::setNodes(const BaseClass& input0, const BaseClass& input1)
{
m_inputNode.push_back(&input0);
m_inputNode.push_back(&input1);
}
Therefore the shared_ptr<>
s must point to const BaseClass
. When you don't want that, you'll have to drop const
from the parameter specifications.
I don't recommend an API like that for your needs. You don't make explicit for the caller, that you remember pointers to the objects. He might pass in stack allocated or even temporary objects, that are not valid any more, when you later try to use them:
myElement.setNodes(createElement0(), createElement1());
Prefer to be explicit about what the user of your function has to expect.
void Element::setNodes(std::shared_ptr<BaseClass> input0,
std::shared_ptr<BaseClass> input1)
{
m_inputNode.push_back(input0);
m_inputNode.push_back(input1);
}
Now the user has to explicitly provide pointers:
myElement.setNodes(std::make_shared<Element>(createElement0()),
std::make_shared<Element>(createElement1()));
This tells the user, that you are going to take shared ownership of that object.
Upvotes: 1
Reputation: 234775
If you know that someone else is managing the lifetime of the vector elements, then use std::vector<const BaseClass*>
as the type, and use &input0
etc. when pushing elements to the vector.
It's difficult to use a std::shared_ptr
pointer here since, at the point of use, you don't know how the object has been created.
If you want to retain your references then you can always enclose them in a std::reference_wrapper
; set std::vector<std::reference_wrapper<const BaseClass>>
as the type. But the ownership issues are still prevalent; you could end up with a vector of dangling references.
Upvotes: 3
Reputation: 545825
Since you stated,
I want a pointer/reference to the original.
The only choice is to drop the shared_ptr
and use a non-owning pointer:
std::vector<BaseClass const*> m_inputNode;
void Element::setNodes(BaseClass const& input0, BaseClass const& input1) {
m_inputNode.push_back(&input0);
m_inputNode.push_back(&input1);
}
(Drop all the const
s if you need a non-const
pointer.)
shared_ptr
fundamentally expresses ownership, which doesn’t seem to be what you’re after.
But if I misunderstood you and you actually want to confer (shared) ownership of the objects to your vector, you need to pass the objects into your function via shared pointers as well:
void Element::setNodes(std::shared_ptr<BaseClass> input0, std::shared_ptr<BaseClass> input1) {
m_inputNode.push_back(input0);
m_inputNode.push_back(input1);
}
Upvotes: 3