多态性和 shared_ptr 通过引用传递
Polymorphism and shared_ptr passed by reference
我尝试使用多态 class 发送给函数 a shared_ptr。
我的 objective 是找到发送我的 shared_ptr 的最佳方式
没有增加 ref_count.
编辑: 我不搜索我的 shared_ptr 被替换的解决方案,因为我想调用 shared_ptr.reset() 例如。
目前,void doGenericTemplate(std::shared_ptr<CLASS>& ptr)
是我想要的结果,但我更喜欢程序中的单个函数。
- 你有其他解决方案吗?
此外,我不明白为什么函数 void doGeneric(std::shared_ptr<Base>& ptr)
不能编译(等同于没有 shared_ptr 工作正常:请检查 doClassic
完整代码)。
- 你有解释吗?
谢谢!
部分代码
#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);
}
完整代码
结论
目前在 c++ 中,shared_ptr 语言中没有特定的工具来使用模板内部 class 的多态性。
最好的方法是重构我的代码并避免管理 shared_ptr(ref_count,重置)。
谢谢大家!
- Do you have another solution ?
通过引用或 const 引用传递对象而不是 shared_ptr
。
void doGeneric(Base& r)
{
r.run();
}
首先 - 这明确表明您没有在某处存储或缓存指针。其次 - 你要避免像你在这里介绍的那样含糊不清。
- Do you have an explain ?
将 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*
.
我尝试使用多态 class 发送给函数 a shared_ptr。 我的 objective 是找到发送我的 shared_ptr 的最佳方式 没有增加 ref_count.
编辑: 我不搜索我的 shared_ptr 被替换的解决方案,因为我想调用 shared_ptr.reset() 例如。
目前,void doGenericTemplate(std::shared_ptr<CLASS>& ptr)
是我想要的结果,但我更喜欢程序中的单个函数。
- 你有其他解决方案吗?
此外,我不明白为什么函数 void doGeneric(std::shared_ptr<Base>& ptr)
不能编译(等同于没有 shared_ptr 工作正常:请检查 doClassic
完整代码)。
- 你有解释吗?
谢谢!
部分代码
#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);
}
完整代码
结论
目前在 c++ 中,shared_ptr 语言中没有特定的工具来使用模板内部 class 的多态性。
最好的方法是重构我的代码并避免管理 shared_ptr(ref_count,重置)。
谢谢大家!
- Do you have another solution ?
通过引用或 const 引用传递对象而不是 shared_ptr
。
void doGeneric(Base& r)
{
r.run();
}
首先 - 这明确表明您没有在某处存储或缓存指针。其次 - 你要避免像你在这里介绍的那样含糊不清。
- Do you have an explain ?
将 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*
.