Reputation: 11562
the idea is that I want a class which is wrapped by std::shared_ptr
, can still be used
just like they weren't a pointer, for example the operator= which was defined in my class
can still be used after my class is wrapped by std::shared_ptr
.
for example
template <class Ty> class shared_ptr_proxy : public std::shared_ptr<Ty> {
public:
template<class Other> shared_ptr_proxy& operator=(const Other& rhs)
{
(*this->get()) = rhs;
return *this;
}
template<class Other> explicit shared_ptr_proxy(Other * ptr)
: std::shared_ptr<Ty>(ptr){};
};
// usage :
shared_ptr_proxy<float> obj = shared_ptr_proxy<float>(new float);
obj = 3.14;
its work, but is there a way that i don't need to create shared_ptr_proxy
or
inheriting a class from std::shared_ptr
?
and
if I do like this, is there a caveat that i should take care of?
Upvotes: 3
Views: 6063
Reputation: 1724
Sorry, I don't think you can get away without inheriting or a custom wrapper, you can not overload operator =
outside the definition of shared_ptr
, and inheritance is not recommended in this case due to the nature of shared_ptr
. However if you write a custom wrapper you can make it generic enough that it works for every type.
It is only possible in C++11, and even there it is difficult. You need decltype
and std::declval
for deducing the return type of the operator, and rvalue references and std::forward
to forward the parameters perfectly. See this question and its answers for examples.
And as mentioned in that question, I have a pointer wrapper class implemented: http://frigocoder.dyndns.org/svn/Frigo/Lang/ref
However it has some differences compared to what you want:
Both operator = (ref&)
and operator = (ref&&)
only copies pointers. However, due to this and the proxied copy constructor, the implicit operator = (const T&)
does a copy construction and a pointer copy instead of assignment or taking the address. This is a conscious choice of mine, assignment can create problems if the object is shared, and taking pointer from a stack allocated object is unsafe.
Taking the return type of compound assignment operators like operator +=
does not work due to an unimplemented feature of GCC. This is no problem since they are reinterpreted: x += y
calls x = (x + y)
, doing a copy/move construction and a pointer copy. This is also a conscious choice of mine, to keep the shared object unchanged.
Garbage collected with Boehm GC instead of reference counted. This is also a conscious choice of mine, reference counting is a pretty bad alternative to garbage collection.
Upvotes: 0
Reputation: 1801
It depends on what you want the proxy for. A full proxy might make it look entirely like you had the value, so you'd provide the conversion operators.
In such case, it might not be a good idea to inherit from shared_ptr
, though, because you might be inheriting functions that you want to rely on the implicit conversions instead.
Compare how sorting orders the items:
#include <memory>
#include <vector>
#include <algorithm>
#include <iostream>
template <class Ty> class shared_ptr_proxy {
std::shared_ptr<Ty> ptr;
public:
template<class Other> explicit shared_ptr_proxy(Other * p)
: ptr(std::shared_ptr<Ty>(p)){};
template<class Other> shared_ptr_proxy& operator=(const Other& other)
{
*ptr = other;
return *this;
}
operator Ty& () { return *ptr; }
operator const Ty& () const { return *ptr; }
};
int main()
{
std::vector<shared_ptr_proxy<int> > vec {
shared_ptr_proxy<int>(new int(10)),
shared_ptr_proxy<int>(new int(11)),
shared_ptr_proxy<int>(new int(9))
};
vec.back() = 8; //use assignment
std::sort(vec.begin(), vec.end()); //sort based on integer (not pointer) comparison
for (unsigned i = 0; i != vec.size(); ++i) {
std::cout << vec[i] << ' '; //output stored values
}
}
#include <memory>
#include <vector>
#include <algorithm>
#include <iostream>
template <class Ty> class shared_ptr_proxy : public std::shared_ptr<Ty> {
public:
template<class Other> explicit shared_ptr_proxy(Other * p)
: std::shared_ptr<Ty>(p){};
template<class Other> shared_ptr_proxy& operator=(const Other& other)
{
*this->get()= other;
return *this;
}
operator Ty& () { return *this->get(); }
operator const Ty& () const { return *this->get(); }
};
int main()
{
std::vector<shared_ptr_proxy<int> > vec {
shared_ptr_proxy<int>(new int(10)),
shared_ptr_proxy<int>(new int(11)),
shared_ptr_proxy<int>(new int(9))
};
vec.back() = 8; //the only thing that works
std::sort(vec.begin(), vec.end()); //sort based on pointer values
for (unsigned i = 0; i != vec.size(); ++i) {
std::cout << vec[i] << ' '; //outputs addresses
}
}
Upvotes: 3
Reputation: 7189
Dereference shared pointer:
std::shared_ptr<float> obj(new float);
*obj = 3.14;
Upvotes: -1
Reputation: 385098
No, you can't do this transparently, and it would probably be quite confusing if you could.
Upvotes: 1
Reputation: 473232
operator=
must be a member of the class that you're overloading. So no, you can't really do that non-intrusively.
Upvotes: 1