accessing operator overloading of class which is wrapped by std::shared_ptr

孤者浪人 提交于 2019-12-08 03:36:57

问题


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?


回答1:


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
    }
}



回答2:


operator= must be a member of the class that you're overloading. So no, you can't really do that non-intrusively.




回答3:


No, you can't do this transparently, and it would probably be quite confusing if you could.




回答4:


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.




回答5:


Dereference shared pointer:

std::shared_ptr<float> obj(new float);
*obj = 3.14;


来源:https://stackoverflow.com/questions/7512378/accessing-operator-overloading-of-class-which-is-wrapped-by-stdshared-ptr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!