【问题标题】:Polymorphism and shared_ptr passed by reference多态性和 shared_ptr 通过引用传递
【发布时间】:2018-02-06 18:46:59
【问题描述】:

我尝试发送一个带有多态类的 shared_ptr 函数。 我的目标是找到一种最好的方式来发送我的 shared_ptr 不增加 ref_count。

编辑:我不搜索替换我的 shared_ptr 的解决方案,因为我想调用 shared_ptr.reset() 例如。

目前,void doGenericTemplate(std::shared_ptr<CLASS>& ptr) 是我想要的结果,但我更喜欢程序中的单个函数。

  1. 您还有其他解决方案吗?

此外,我不明白为什么函数 void doGeneric(std::shared_ptr<Base>& ptr) 无法编译(等效于没有 shared_ptr 工作正常:请查看完整代码中的 doClassic)。

  1. 你有解释吗?

谢谢!

部分代码

#include <iostream>
#include <memory>

class Base
{
    public:
        Base() = default;
        virtual ~Base() = default;
        virtual void run() = 0;
};

class Derived1: public Base
{
    public:
        Derived1() = default;
        virtual ~Derived1() = default;
        void run()
        {
            std::cout << "  Derived1";
        }
};

class Derived2: public Base
{
    public:
        Derived2() = default;
        virtual ~Derived2() = default;
        void run()
        {
            std::cout << "  Derived2";
        }
};

// This function works but increase count
void doGenericCopy(std::shared_ptr<Base> ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

// This function works without increase count = OK !
void doSpecificD1(std::shared_ptr<Derived1>& ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

// Compilation error = FAILED !
void doGeneric(std::shared_ptr<Base>& ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

// Working fine for all Derivate = OK !
template<typename CLASS>
void doGenericTemplate(std::shared_ptr<CLASS>& ptr)
{
    ptr->run();
    std::cout << "  Ref count: " << ptr.use_count() << std::endl;
}

int main()
{
    auto d1 = std::make_shared<Derived1>();
    auto d2 = std::make_shared<Derived2>();

    std::cout << "With copy: " << std::endl;
    doGenericCopy(d1);
    doGenericCopy(d2);

    std::cout << "Specific: " << std::endl;
    doSpecificD1(d1);

    std::cout << "Template: " << std::endl;
    doGenericTemplate(d1);
    doGenericTemplate(d2);

    // Compilation issue
    //doGeneric(d1);
}

完整代码

https://ideone.com/ZL0v7z

结论

目前在 c++ 中,shared_ptr 在语言中还没有特定的工具来使用模板内类的多态性。

最好的方法是重构我的代码,避免管理 shared_ptr (ref_count, reset)。

谢谢大家!

【问题讨论】:

标签: c++ c++11 polymorphism pass-by-reference


【解决方案1】:
  1. 您还有其他解决方案吗?

通过引用或 const 引用而不是 shared_ptr 传递对象。

void doGeneric(Base& r)
{
    r.run();
}

首先 - 这明确表明您没有在某处存储或缓存指针。其次 - 您避免像您在此处介绍的那样模棱两可。

  1. 你有解释吗?

shared_ptr&lt;Derived&gt; 传递给函数会导致隐式转换为shared_ptr&lt;Base&gt;。这个新的shared_ptr&lt;Base&gt; 是临时的,因此不能转换为shared_ptr&lt;Base&gt; &amp;。即使您可以通过,这种隐式转换也会增加引用计数。

【讨论】:

    【解决方案2】:

    shared_ptr&lt;Base&gt;shared_ptr&lt;Derived&gt; 是不相关的类型,除非您可以从 shared_ptr&lt;Derived&gt; 隐式创建 shared_ptr&lt;Base&gt;

    这个创建增加了一个引用计数。

    如果您真的非常想避免引用计数...

    template<class T>
    struct shared_ptr_view {
      template<class D>
      shared_ptr_view( std::shared_ptr<D>& sptr ):
        vtable( get_vtable<D>() ),
        ptr( std::addressof(sptr) )
      {}
      shared_ptr_view( shared_ptr_view const& ) = default;
      shared_ptr_view() = default;
      shared_ptr_view& operator=( shared_ptr_view const& ) = delete;
      T* get() const { if(vtable) return vtable->get(ptr); return nullptr; }
      void clear() const { if(vtable) vtable->clear(ptr); }
      std::shared_ptr<T> copy() const { if(vtable) return vtable->copy(ptr); return {} }
      operator std::shared_ptr<T>() const { return copy(); }
      T* operator->() const { return get(); }
      T& operator*() const { return *get(); }
      explicit operator bool() const { return get(); }
      std::size_t use_count() const { if (vtable) return vtable->use_count(ptr); return 0; }
    private:
      struct vtable_t {
        T*(*get)(void*) = 0;
        std::shared_ptr<T>(*copy)(void*) = 0;
        void(*clear)(void*) = 0;
        std::size_t(*use_count)(void*) = 0;
      };
      vtable_t const* vtable = 0;
      void* ptr = 0;
      template<class D>
      static vtable_t create_vtable() {
        return {
          [](void* ptr)->T*{ return static_cast<std::shared_ptr<D>*>(ptr)->get(); },
          [](void* ptr)->std::shared_ptr<T>{ return *static_cast<std::shared_ptr<D>*>(ptr); },
          [](void* ptr){ static_cast<std::shared_ptr<D>*>(ptr)->reset(); },
          [](void* ptr){ return static_cast<std::shared_ptr<D>*>(ptr)->use_count(); }
        };
      }
      template<class D>
      static vtable_t const* get_vtable() {
        static const auto vtable = create_vtable<D>();
        return &vtable;
      }
    };
    

    然后

    void doGeneric( shared_ptr_view<Base> ptr ) {
      ptr->run();
      std::cout << "  Ref count: " << ptr.use_count() << std::endl;
    }
    

    不会增加引用计数。我认为这是原始的精神错乱。

    shared_ptr_view.clear() 有效,但 shared_ptr_view.reset(T*) 不能:不能将 shared_ptr_view&lt;Derived&gt; 重置为指向 Base*

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-21
      • 2016-12-18
      • 1970-01-01
      • 2012-01-13
      • 2016-09-05
      • 2023-04-07
      • 2012-10-10
      • 2011-01-23
      相关资源
      最近更新 更多