是否确定从C ++ 11智能指针,继承和覆盖相对运营商?(Is it OK to inherit f

2019-07-31 19:52发布

据cppreference.com , std::shared_ptr提供了一整套相对运算符(==,!=,<,...),但没有规定比较语义。 我认为他们的底层裸指针比较被引用的对象和标准:: weak_ptr的和std ::的unique_ptr这样做。

出于某些目的,我宁愿这个顺序基础上,引用的对象比较(而不是指向它们的指针)的智能指针相对运营商。 这已经是我做的事情很多,但其行为大多喜欢除了运营商相对原始指针我自己的“哑指针”。 我想这样做与标准C ++ 11个智能指针同样的事情。 所以...

  1. 是否确定从C ++ 11智能指针(shared_ptr的,weak_ptr的和的unique_ptr)继承和覆盖相对运营商?

  2. 是否有我需要看出来的任何偷偷摸摸的问题是什么? 例如,是否有我需要实现或使用任何其他方式using的,以确保事情正常工作?

  3. 对于懒惰最终,有没有可用库中的模板,这将自动为我做到这一点?

我希望这是一个“你当然能做到这一点,白痴!” 之类的话,但我有点不确定,因为在标准库的一些类(容器,如std::map至少),你不应该继承。

Answer 1:

在一般情况下,它不是安全地从任何谁的析构函数不是动态的继承。 它可以是,通常做,你就必须非常小心。 相反,从指针继承的,我只是用的组合物,特别是因为会员的数量相对较少。 你也许可以做一个模板类此

template<class pointer_type>
class relative_ptr {
public:
    typedef typename std::pointer_traits<pointer_type>::pointer pointer;
    typedef typename std::pointer_traits<pointer_type>::element_type element_type;
    relative_ptr():ptr() {}
    template<class U>
    relative_ptr(U&& u):ptr(std::forward<U>(u)) {}
    relative_ptr(relative_ptr<pointer>&& rhs):ptr(std::move(rhs.ptr)) {}
    relative_ptr(const relative_ptr<pointer>& rhs):ptr(std::move(rhs.ptr)) {}

    void swap (relative_ptr<pointer>& rhs) {ptr.swap(rhs.ptr);}
    pointer release() {return ptr.release();}
    void reset(pointer p = pointer()) {ptr.reset(p);}
    pointer get() const {return ptr.get();}
    element_type& operator*() const {return *ptr;}
    const pointer_type& operator->() const {return ptr;}

    friend bool operator< (const relative_ptr& khs, const relative_ptr& rhs) const 
    {return std::less<element>(*lhs,*rhs);}
    friend bool operator<=(const relative_ptr& khs, const relative_ptr& rhs) const 
    {return std::less_equal<element>(*lhs,*rhs);}
    friend bool operator> (const relative_ptr& khs, const relative_ptr& rhs) const 
    {return std::greater<element>(*lhs,*rhs);}
    friend bool operator>=(const relative_ptr& khs, const relative_ptr& rhs) const 
    {return std::greater_equal<element>(*lhs,*rhs);}
    friend bool operator==(const relative_ptr& khs, const relative_ptr& rhs) const 
    {return *lhs==*rhs;}
    friend bool operator!=(const relative_ptr& khs, const relative_ptr& rhs) const 
    {return *lhs!=*rhs;}
protected:
    pointer_type ptr;
};

显然,包装的简单降低你的智能指针,但无论最小公分母。 他们不完全是复杂的,你可以做一个对每个智能指针类。

我提供的,我不喜欢的方式警告==作品,因为它可能有两个指向不同的对象返回true。 但是无所谓。 我还没有测试的代码,它可能会失败某些任务,比如尝试当它包含的unique_ptr复制。



Answer 2:

首先,正如其他人已经指出的是,继承不是要走的路。 但是,而不是被接受的答案提出的令人费解的包装,我会做一些简单得多:实现自己的比较为自己的类型:

namespace myns {
struct mytype {
   int value;
};
bool operator<( mytype const& lhs, mytype const& rhs ) {
   return lhs.value < rhs.value;
}
bool operator<( std::shared_ptr<mytype> const & lhs, std::shared_ptr<mytype> const & rhs )
{
   // Handle the possibility that the pointers might be NULL!!!
   // ... then ...
   return *lhs < *rhs;
}
}

神奇的,这是不是真的魔法都为参数依赖查找(亦称Koening查找或ADL)。 当编译器遇到一个函数调用它会增加的参数来查找命名空间。 如果对象是一个模板实例,那么编译器也将增加用于实例化模板类型的命名空间。 所以:

int main() {
   std::shared_ptr<myns::mytype> a, b;
   if ( a < b ) {                       // [1]
      std::cout << "less\n";
   } else {
      std::cout << "more\n";
   }
}

在[1],并且由于ab都是对象用户定义的类型 (*)ADL将踢,它都将添加stdmyns到查找集。 然后它会找到的标准定义operator<std::shared_ptr是:

template<class T, class U>
bool std::operator<(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;

它也将增加myns ,并添加:

bool myns::operator<( mytype const& lhs, mytype const& rhs );

然后,查询结束后,重载解析踢,这将决定myns::operator<是一个更好的比赛比std::operator<呼叫,因为它是一个完美的匹配,并在这种情况下,非模板采取偏好。 然后它会调用自己的operator<而不是标准之一。

这将成为更令人费解的一点,如果你的类型实际上是一个模板,如果是,删除一个评论,我将延长答复。


(*)这是一个微小的简化。 因为operator<可以实现既作为成员函数或自由函数,编译器将检查里面std::shared_ptr<>对于构件operator< (不存在于标准)和朋友。 它还将往里mytypefriend功能...等。 但最终会找到合适的人。



Answer 3:

这是危险的从支持分配和拷贝构造,由于不小心将其分配给一个基类变量减少一半派生类实例的任何风险类继承。 这会影响大多数类,几乎是不可能避免,因而对部分时,他们周围复制实例类的用户需要警惕。

正因为如此,班旨在为基地平时工作,应不支持复制。 当复制是必要的,他们应该提供类似Derived* clone() const override代替。

你正在试图解决问题可能是最好的东西留下,因为他们是与这样的指针工作时提供定制解决比较。

std::vector<std::shared_ptr<int>> ii = …;
std::sort(begin(ii), end(ii),
          [](const std::shared_ptr<int>& a, const std::shared_ptr<int>& b) {
              return *a < *b;
          });


文章来源: Is it OK to inherit from the C++11 smart pointers and override the relative operators?