Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从C++;11个智能指针和重写相关运算符?_C++_Inheritance_C++11_Operator Overloading_Smart Pointers - Fatal编程技术网

C++ 从C++;11个智能指针和重写相关运算符?

C++ 从C++;11个智能指针和重写相关运算符?,c++,inheritance,c++11,operator-overloading,smart-pointers,C++,Inheritance,C++11,Operator Overloading,Smart Pointers,根据std::shared_ptr提供了一整套相对运算符(=,!=,),一般来说,从任何非动态析构函数继承都是不安全的。通常可以这样做,也可以这样做,你只需非常小心。 我不从指针继承,而是使用组合,尤其是因为成员数量相对较少。 您可以为此创建一个模板类 template<class pointer_type> class relative_ptr { public: typedef typename std::pointer_traits<pointer_type>

根据std::shared_ptr提供了一整套相对运算符(=,!=,),一般来说,从任何非动态析构函数继承都是不安全的。通常可以这样做,也可以这样做,你只需非常小心。 我不从指针继承,而是使用组合,尤其是因为成员数量相对较少。 您可以为此创建一个模板类

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;
};
模板
类相对ptr{
公众:
typedef typename std::pointer_traits::pointer-pointer;
typedef typename std::pointer_traits::element_type element_type;
相对ptr():ptr(){}
模板
相对ptr(U&&U):ptr(std::forward(U)){
相对ptr(相对ptr&&rhs):ptr(std::move(rhs.ptr)){}
相对ptr(const relative ptr&rhs):ptr(std::move(rhs.ptr)){
无效交换(相对的){ptr.swap(rhs.ptr);}
指针释放(){return ptr.release();}
无效重置(指针p=pointer()){ptr.reset(p);}
指针get()常量{return ptr.get();}
元素类型&运算符*()常量{return*ptr;}
常量指针类型和运算符->()常量{return ptr;}
friend bool运算符<(常数相对值和khs,常数相对值和rhs)常数
{返回std::less(*lhs,*rhs);}
friend bool运算符(常数相对值和khs、常数相对值和rhs)常数
{返回标准::更大(*lhs,*rhs);}
友元布尔运算符>=(常数相对值\u ptr&khs,常数相对值\u ptr&rhs)常数
{return std::greater_equal(*lhs,*rhs);}
friend bool运算符==(常量相对\u ptr&khs,常量相对\u ptr&rhs)常量
{return*lhs==*rhs;}
友元布尔运算符!=(常数相对值\u ptr&khs,常数相对值\u ptr&rhs)常数
{return*lhs!=*rhs;}
受保护的:
指针式ptr;
};
显然,包装器的简单性将智能指针降低到了最低公分母,但无论如何,它们并不复杂,可以为每个智能指针类创建一个


我将提供一个警告,我不喜欢
==
的工作方式,因为它可能会在指向不同对象的两个指针上返回true。但不管怎样。我还没有测试代码,它可能会在某些任务中失败,比如当它包含唯一的\u ptr时尝试复制。

从任何支持赋值的类继承是危险的和复制构造,这是由于意外地将派生类实例分配给基类变量会有将派生类实例切成两半的风险。这会影响大多数类,并且几乎不可能防止,因此每当类的用户复制实例时,都需要提高警惕

因此,打算用作基类的类通常不支持复制。当需要复制时,它们应该提供类似于
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;
          });
std::vector ii=…;
标准::排序(开始(ii),结束(ii),
[](常数标准::共享\u ptr&a,常数标准::共享\u ptr&b){
返回*a<*b;
});

正如其他人已经指出的那样,第一件事是继承不是一条可行之路。但与公认的答案所建议的复杂包装不同,我想做一些更简单的事情:为自己的类型实现自己的比较器:

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;
}
}
它还将添加
myns
并添加:

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

bool myns::operator在一般情况下,从任何析构函数不是动态的对象继承都是不安全的。通常可以这样做,但你必须非常小心。@Mooing Duck-好的,没有后期绑定,这可能是析构函数和其他地方的问题-是有意义的。我不认为这对我来说是个问题,至少目前如此,但我需要检查一下。也许将智能指针包装为成员比继承更好。呃,所谓“动态”,我当然是指“虚拟”我认为你的做法是完全错误的。如果你有一个指向某个对象的指针,并且你想得到该对象,你就要取消对该指针的引用。这里应用了一个非常基本的思想:想与智能指针指向的对象进行比较吗?取消对它们的引用。智能指针应该像指针一样工作。编写一个比较函数,如
dereference_compare
这是您想要的,将概念分开。也许另一种选择是您的目的(如您所说)接受用于排序的比较器。例如,
std::set
不同于
std::set>
(其中,
indirect\u less
留给读者想象,但应该是显而易见的)。关于“因为两个指向不同对象的指针可能返回true”是的,但同样的情况也适用于正常的例子。把这些看作是代理,恰好也就是智能指针——指针比提供的抽象更为具体的实现细节。我早该说了,但是C++中也有先例,指针像代理一样,不需要被撤销。de>&
引用也称为自去引用指针。比这个用例实际需要的要复杂一些…:)我会在适当的时候这样做,但正如我在各种评论中指出的那样,这需要传递更多的东西,并且可能会混淆。当您知道将这两个东西一起使用才是正确的时候,将它们打包在一起可以确保它们一起移动,而静态键入可以提供额外的检查。而“指针”这个名称可能有误导性-这更像是一种代理,不管是否存在网络问题-这并不意味着以这种方式打包功能是一件坏事。@Steve314我真的不明白你在评论中的意思。类型名称空间中的自由函数是相同的一部分
template<class T, class U>
bool std::operator<(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept;
bool myns::operator<( mytype const& lhs, mytype const& rhs );