【问题标题】:accessing operator overloading of class which is wrapped by std::shared_ptr访问由 std::shared_ptr 包装的类的运算符重载
【发布时间】:2011-11-22 15:58:56
【问题描述】:

我的想法是我想要一个由std::shared_ptr 包装的类,仍然可以使用 就像它们不是指针一样,例如在我的班级中定义的 operator= 我的课被std::shared_ptr包裹后仍然可以使用。

例如

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;

它的工作,但有没有一种方法我不需要创建shared_ptr_proxy 或 从std::shared_ptr继承一个类?

如果我这样做了,有什么需要注意的地方吗?

【问题讨论】:

  • 有什么理由不能只取消引用指针吗? *ptrA = *ptrB;?
  • 因为这个想法是为了隐藏它实际上是一个指针
  • 知道它实际上是一个指针通常是共享可变数据的一个特性。否则,不同对象可能对同一事物产生别名并不明显,因此a = b 可以更改c 的值。毫无疑问,在某些情况下你确实想隐藏它是一个指针,对我来说最明显的是它实际上并没有共享(尽管使用了shared_ptr),它是一个 pImpl。

标签: c++ inheritance stl overloading shared-ptr


【解决方案1】:

对不起,我不认为没有继承或自定义包装器就无法逃脱,不能在shared_ptr 的定义之外重载operator =,由于@ 的性质,在这种情况下不建议使用继承987654325@。但是,如果您编写自定义包装器,则可以使其具有足够的通用性,使其适用于每种类型。

只有在 C++11 中才有可能,即使在那里也很难。您需要decltypestd::declval 来推断运算符的返回类型,以及右值引用和std::forward 来完美转发参数。有关示例,请参阅 this question 及其答案。

正如那个问题中提到的,我实现了一个指针包装类:http://frigocoder.dyndns.org/svn/Frigo/Lang/ref

但是与您想要的相比,它有一些不同:

  • operator = (ref&amp;)operator = (ref&amp;&amp;) 都只复制指针。但是,由于这个和代理的复制构造函数,隐式 operator = (const T&amp;) 执行复制构造和指针复制,而不是分配或获取地址。这是我有意识的选择,如果对象是共享的,赋值会产生问题,并且从堆栈分配的对象中获取指针是不安全的。

  • 由于 GCC 的一个未实现的特性,采用复合赋值运算符(如 operator +=)的返回类型不起作用。这没有问题,因为它们被重新解释:x += y 调用x = (x + y),进行复制/移动构造和指针复制。这也是我有意识的选择,保持共享对象不变。

  • 使用 Boehm GC 收集的垃圾而不是引用计数。这也是我有意识的选择,引用计数是垃圾收集的一个非常糟糕的替代方案。

【讨论】:

    【解决方案2】:

    这取决于您希望代理做什么。一个完整的代理可能会让它看起来完全像你有价值,所以你会提供转换运算符。

    在这种情况下,从shared_ptr 继承可能不是一个好主意,因为您可能正在继承要依赖隐式转换的函数。

    比较项目的排序方式:

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

    【讨论】:

      【解决方案3】:

      取消引用共享指针:

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

      【讨论】:

        【解决方案4】:

        不,你不能透明地做到这一点,如果可以的话,它可能会很混乱。

        【讨论】:

          【解决方案5】:

          operator= 必须是您要重载的类的成员。所以不,你不能真正做到非侵入式。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-09-27
            • 2014-02-20
            • 1970-01-01
            • 1970-01-01
            • 2013-02-16
            相关资源
            最近更新 更多