参考

时间:2018-02-06 18:46:59

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

我尝试发送带有多态类的shared_ptr函数。 我的目标是找到发送我的shared_ptr的最佳方式 没有增加ref_count。

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

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

  1. 你有其他解决方案吗?
  2. 此外,我不明白为什么函数void doGeneric(std::shared_ptr<Base>& ptr)没有编译(相当于没有shared_ptr工作正常:请在完整代码中检查doClassic)。

    1. 你有解释吗?
    2. 谢谢!

      部分代码

      #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)。

      谢谢你们!

2 个答案:

答案 0 :(得分:2)

  
      
  1. 你有其他解决方案吗?
  2.   

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

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

首先 - 这明确表明你没有存储或缓存指针somwhere。其次 - 你可以避免像你在这里提到的那样含糊不清。

  
      
  1. 你有解释吗?
  2.   

shared_ptr<Derived>传递给函数会导致隐式强制转换为shared_ptr<Base>。这个新shared_ptr<Base>是临时的,因此无法转换为shared_ptr<Base> &。即使您可以传递它,这种隐式转换也会增加引用计数。

答案 1 :(得分:2)

shared_ptr<Base>shared_ptr<Derived>是不相关的类型,但您可以隐式地从shared_ptr<Base>创建shared_ptr<Derived>

此创建添加引用计数。

如果你真的,真的想避免引用计数......

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<Derived>无法重置为指向Base*