shared::ptr
我发现的实现是这样写的
namespace detail {
struct deleter_base {
virtual ~deleter_base() {}
virtual void operator()( void* ) = 0;
};
template <typename T>
struct deleter : deleter_base {
virtual void operator()( void* p ) {
delete static_cast<T*>(p);
}
};
}
template <typename T>
class simple_ptr {
T* ptr;
detail::deleter_base* deleter;
public:
template <typename U>
simple_ptr( U* p ) {
ptr = p;
deleter = new detail::deleter<U>();
}
~simple_ptr() {
(*deleter)( ptr );
delete deleter;
}
};
我的问题是
1) 为什么我们需要这样的结构(我的意思是类似于类型删除技术),难道我们不能把它作为删除器(见下面的代码)吗?在这里有一个虚拟函数的目的是什么,据我所知,如果它不是虚拟的,它无论如何都会调用 delete
在正确的类型上(即在 Bar
上键入 std::shared_ptr<Foo>(new Bar)
),因为 simple_ptr
具有模板化构造函数。
template <typename T>
struct deleter {
void operator()( void* p ) {
delete static_cast<T*>(p);
}
};
2) 为什么我们需要在基类中使用虚析构函数?仅仅是因为它包含一个虚函数还是我们的删除器也必须有虚析构函数?
最佳答案
共享指针类型删除破坏,因为它们已经必须处理引用计数。一路打到删除破坏并没有那么昂贵。
如果您希望能够将指向 T 的共享指针转换为指向 void 的共享指针,则需要类型删除销毁,这有时很有用。通常,它不需要您存储的数据具有虚拟析构函数。
此外,它允许别名共享指针指向共享指针拥有的资源内。
你的删除器显然不起作用;由于它缺少一个公共(public)基类,它只能被普遍存储在 void*
中。 , 你不能调用 void*
用(ptr)
.
忽略你的 shared::ptr
,如果我们看工业质量std::shared_ptr
,我们发现引用控制 block 在其末尾存储了类型删除的删除器,如果你 make_shared
它用对象的实例替换类型删除的删除器。
struct rc_block {
std::atomic<std::size_t> strong;
std::atomic<std::size_t> weak;
virtual void cleanup() = 0;
virtual ~rc_block() {}
};
template<class T>
struct maked_rc_block final {
std::atomic<std::size_t> strong = 1;
std::atomic<std::size_t> weak = 0;
std::aligned_storage<sizeof(T), alignof(T)> t;
template<class... Args>
maked_rc_block(Args&&...args) {
::new( (void*)&t ) T(std::forward<Args>(args)...);
}
void cleanup() override {
((T*)&t)->~T();
}
};
template<class F>
struct action_rc_block final {
std::atomic<std::size_t> strong = 1;
std::atomic<std::size_t> weak = 0;
F f;
void cleanup() { f(); }
template<class IN>
actoin_rc_block(IN&& in):f(std::forward<IN>(in)) {}
};
template<class F>
action_rc_block(F)->action_rc_block<F>;
template<class T>
struct simple_shared {
T* ptr = 0;
rc_block* counters = 0;
simple_shared( simple_shared const& o ):
ptr(o.ptr), counters(o.counters)
{ if (counters) ++(counters->strong); }
~simple_shared() {
if (counters && --(counters->strong)) {
delete counters;
}
}
template<class U>
simple_shared(U* in):
ptr(in),
counters( new action_rc_block{[in]{ delete in; }} )
{}
// explicit deleter
template<class U, class D>
simple_shared(U* in, D&& d):
ptr(in),
counters( new action_rc_block{[in,d=std::forward<D>(d)]{ d(in); }} )
{}
template<class U, class V>
simple_shared(simple_shared<U> const& alias_this, V* v):
ptr(v),
counters(alias_this.counters)
{
if(counters) ++(counters->strong);
}
template<class U>
simple_shared( maked_rc_block<U>* c ):
ptr( c?(T*)&c.t:nullptr ),
counters(c)
{}
};
template<class T, class...Args>
simple_shared<T> make_simple_shared( Args&&... args ) {
auto* counter = new make_rc_block<T>( std::forward<Args>(args)... );
return {counter};
}
我对原子的使用快速而松散,但我希望你明白这一点。
关于c++ - std::shared_ptr 控制 block 中的虚函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52955844/