std::shared_ptr
有一个漂亮的模板化构造函数,可以自动为其给定类型创建正确的删除器(该链接中的构造函数2)。
直到现在,我(错误地)认为std::unique_ptr
有一个类似的构造函数,但是当我运行以下代码时:
#include <memory>
#include <iostream>
// Notice nothing is virtual
struct Foo
{
~Foo() { std::cout << "Foo\n"; }
};
struct Bar : public Foo
{
~Bar() { std::cout << "Bar\n"; }
};
int main()
{
{
std::cout << "shared_ptr:\n";
std::shared_ptr<Foo> p(new Bar()); // prints Bar Foo
}
{
std::cout << "unique_ptr:\n";
std::unique_ptr<Foo> p(new Bar()); // prints Foo
}
}
什么是一种干净,简单且正确的方法来创建一个unique_ptr
为其给定指针具有正确删除器的对象?特别是如果我想存储这些的完整列表(即std::vector<std::unique_ptr<Foo>>
),这意味着它们都必须具有异构类型?
(原谅可怜的头衔;随时提出更好的头衔)
这是一种方法:
{
std::cout << "unique_ptr<Bar, void(void*)>:\n";
std::unique_ptr<Foo, void(*)(void*)> p(
new Bar(), [](void*p) -> void { delete static_cast<Bar*>( p ); }
); // prints Bar Foo
}
这种方法的主要问题是unique_ptr
支持转换为逻辑“指向基类的指针”,但是该标准不保证转换为void*
将会产生相同的地址。实际上,如果基类是非多态的,而派生类是多态的,这只是一个问题,这会引入vtable ptr并因此可能会稍微改变内存布局。但是,在这种可能(但不太可能)的情况下,在删除器中进行回退将产生不正确的指针值并爆炸。
因此,上述内容对于此类转换在形式上并不安全。
要与do大致相同shared_ptr
(shared_ptr
支持转换为从逻辑指针到基址的指针),您还需要将原始void*
指针与删除器一起存储。
通常,当您控制最顶层的基类时,请将其析构函数设为虚拟。
这样就可以了。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句