问题实际上与标题相符:我很好奇知道这种差异的技术原因,以及背后的逻辑?
std::shared_ptr<void> sharedToVoid; // legal;
std::unique_ptr<void> uniqueToVoid; // ill-formed;
问题实际上与标题相符:我很好奇知道这种差异的技术原因,以及背后的逻辑?
std::shared_ptr<void> sharedToVoid; // legal;
std::unique_ptr<void> uniqueToVoid; // ill-formed;
std::shared_ptr
实现了类型擦除,而std::unique_ptr
没有。
template<class T,class Deleter = std::default_delete<T> >
class unique_ptr;
Deleter
的情况下,同时template<class T>
class shared_ptr;
没有它。
shared_ptr
要实现类型擦除呢?嗯,它这样做是因为它需要支持引用计数,并且为了支持引用计数,它必须从堆中分配内存,而且由于它必须分配内存,它进一步实现了类型擦除 - 这也需要堆分配内存。所以基本上它只是机会主义而已!
由于类型擦除,std::shared_ptr
能够支持两个功能:
void*
,但在销毁时仍然能够正确调用它们的析构函数以正确删除对象。好了,这就是关于std::shared_ptr
的工作原理的全部内容。
std::unique_ptr
能否将对象存储为void*
?答案是,是的——只要您传递一个合适的删除器作为参数。以下是一个这样的示例演示:int main()
{
auto deleter = [](void const * data ) {
int const * p = static_cast<int const*>(data);
std::cout << *p << " located at " << p << " is being deleted";
delete p;
};
std::unique_ptr<void, decltype(deleter)> p(new int(959), deleter);
} //p will be deleted here, both p ;-)
959 located at 0x18aec20 is being deleted
unique_ptr
中使用适当的std::function
作为删除器类型来实现这一点。假设这确实有效,那么你就完成了,既有独占所有权,又有类型擦除的删除器。std::function
,因为似乎不是必需的)。using unique_void_ptr = std::unique_ptr<void, void(*)(void const*)>;
template<typename T>
auto unique_void(T * ptr) -> unique_void_ptr
{
return unique_void_ptr(ptr, [](void const * data) {
T const * p = static_cast<T const*>(data);
std::cout << "{" << *p << "} located at [" << p << "] is being deleted.\n";
delete p;
});
}
int main()
{
auto p1 = unique_void(new int(959));
auto p2 = unique_void(new double(595.5));
auto p3 = unique_void(new std::string("Hello World"));
}
{Hello World} located at [0x2364c60] is being deleted.
{595.5} located at [0x2364c40] is being deleted.
{959} located at [0x2364c20] is being deleted.
template<typename T, typename... Args>
auto make_unique_void(Args&&... args)
{
return unique_void(new T(std::forward<Args>(args)...));
}
其中一个理由是在许多使用情况下的shared_ptr
中 - 也就是作为生命周期指示器或哨兵。
这在原始的boost文档中有所提及:
auto register_callback(std::function<void()> closure, std::shared_ptr<void> pv)
{
auto closure_target = { closure, std::weak_ptr<void>(pv) };
...
// store the target somewhere, and later....
}
void call_closure(closure_target target)
{
// test whether target of the closure still exists
auto lock = target.sentinel.lock();
if (lock) {
// if so, call the closure
target.closure();
}
}
其中 closure_target
大概是这样的:
struct closure_target {
std::function<void()> closure;
std::weak_ptr<void> sentinel;
};
struct active_object : std::enable_shared_from_this<active_object>
{
void start() {
event_emitter_.register_callback([this] { this->on_callback(); },
shared_from_this());
}
void on_callback()
{
// this is only ever called if we still exist
}
};
shared_ptr<X>
总是可以转换为shared_ptr<void>
,所以事件发射器现在可以完全不必关心它所调用的对象类型。weak_ptr<void>::lock
是一个同步操作。
D
,仍然可以创建一个std::unique_ptr<void, D>
来使其更好。 - Angew is no longer proud of SOunique_ptr
中使用适当的std::function
作为删除器类型来实现。假设这确实有效,那么你就完成了,具有独占所有权和类型擦除的删除器。 - Steve Jessopstd::function
提供的任何其他类型抹除中需要使用std::function
。只需将指向实例化或您的deleter<T>
的指针作为删除器传递,这就是您在此示例中所需的所有“类型抹除”。根本不需要涉及std::function
。请参见:http://coliru.stacked-crooked.com/a/3b2c04aadc638a02 我们应该询问@Steve Jessop关于他对std::function
的引用意义。 - AnT stands with Russiastd::function
是不必要的,因为在具有相同指针类型的指针内部已知T
。我已经更改了示例。感谢您的指出。 :-) - Nawaz