Reputation: 3348
I have a function that looks like:
// this function might modify base_ptr
void SomeFunction(shared_ptr<Base> &base_ptr)
{ if(some_condition) { base_ptr = some_other_ptr; } }
I'd like to call the function with a shared_ptr:
shared_ptr<Derived> d = ...;
SomeFunction(d);
This doesn't work though. It doesn't work if I'm using normal pointers either (ie. implicit casting to Base* & from Derived*. One workaround is to create a Base pointer from the Derived one, and then pass that to the function.
shared_ptr<Base> base = d;
SomeFunction(b);
But this isn't very pretty from a coding standpoint. It also adds confusion and the potential for a subtle bug:
shared_ptr<Derived> d = derived;
shared_ptr<Base> b = derived;
SomeFunction(b);
// b and d might now be pointing to different things -- not good!
Is there better way to do this?
Upvotes: 2
Views: 77
Reputation: 43662
You could template the function for the smart pointer's type
#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;
class Base {
public:
virtual void hello() {
cout << "hello base" << endl;
}
};
class Derived : public Base {
public:
void hello() {
cout << "hello derived" << endl;
}
};
class otherClass {
public:
};
template<typename T>
void SomeFunction(shared_ptr<T> &base_ptr)
{
static_assert(is_base_of<Base, T>::value == true, "Wrong non-derived type");
base_ptr->hello();
// Rebase it
base_ptr.reset(new Derived);
base_ptr->hello();
}
int main() {
shared_ptr<Base> obj(new Base());
SomeFunction(obj);
// hello base
// hello derived
shared_ptr<Derived> obj2(new Derived());
// hello derived
// hello derived
SomeFunction(obj2);
shared_ptr<otherClass> obj3(new otherClass());
SomeFunction(obj3); // ASSERT
return 0;
}
If you intend to update all the smart pointers when you reset one, you'll have to do some book-keeping by yourself since they're not designed to have a "signal-like" mechanism to notify other smart pointers pointing to the same object.
Edited my answer to provide compile-time safety if you intend to use it with Base and relative subclasses.
Warning: the above solution uses C++11, the same could be accomplished in a similar way in pre-C++11 code
Upvotes: 1
Reputation: 64308
What you are trying to do is inherently dangerous, and C++ is making it hard on purpose. Consider if C++ allowed you to call SomeFunction
the way you wanted. Then you could do this:
struct Base {
};
struct Derived1 : Base {
void f1();
};
struct Derived2 : Base {
void f2();
};
void SomeFunction(shared_ptr<Base> &p)
{
p = make_shared<Derived2>(); // nothing wrong with converting
// a Derived2 pointer to a Base pointer.
}
int main()
{
shared_ptr<Derived1> d = make_shared<Derived1>();
SomeFunction(d); // An error, but what if it wasn't?
d->f1(); // Trying to call method f1 of a Derived2!
}
The compiler would not be able to know that d
changed from a Derived1
pointer to a Derived2
pointer, so it wouldn't be able to give you a compile error when you tried to call method f1
of a Derived2
.
Upvotes: 2