多态性和共享_ptr通过引用传递

Polymorphism and shared_ptr passed by reference

本文关键字:引用 ptr 共享 多态性      更新时间:2023-10-16

我尝试发送到具有多态性类的共享_ptr。我的目标是找到发送我的共享_ptr的最佳方法不增加ref_count。

edit:我不搜索我的共享_ptr的地方,因为我想调用shared_ptr.reset((。

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

  1. 您还有另一个解决方案吗?

此外,我不明白为什么该函数void doGeneric(std::shared_ptr<Base>& ptr)不编译(如果没有共享的_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 中,共享_ptr在语言中没有一种特定的工具来使用模板中类的多态性。

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

谢谢大家!

  1. 您还有另一个解决方案吗?

通过参考或const引用而不是shared_ptr

传递对象。
void doGeneric(Base& r)
{
    r.run();
}

首先 - 这明确表示您不存储或缓存指针。其次 - 您避免像您在此处呈现的歧义一样。

  1. 您有解释吗?

shared_ptr<Derived>传递到功能导致隐式铸造到shared_ptr<Base>。这个新的shared_ptr<Base>是暂时的,因此不能将其施加到shared_ptr<Base> &。即使您可以通过,这种隐式演员也会增加裁判数量。

a shared_ptr<Base>shared_ptr<Derived>是无关的类型,除了您可以从shared_ptr<Derived>中隐式创建shared_ptr<Base>

此创建添加了参考数。

如果您真的要避免参考计数...

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*