C++ 有没有一种方便的方法来获得唯一的\u ptr,从而自动拥有一个类似于共享\u ptr的删除器?
有一个漂亮的模板构造函数,自动为其给定类型创建正确的删除器(该链接中的构造函数#2) 直到现在,我(错误地)认为我有一个类似的构造函数,但当我运行以下代码时:C++ 有没有一种方便的方法来获得唯一的\u ptr,从而自动拥有一个类似于共享\u ptr的删除器?,c++,C++,有一个漂亮的模板构造函数,自动为其给定类型创建正确的删除器(该链接中的构造函数#2) 直到现在,我(错误地)认为我有一个类似的构造函数,但当我运行以下代码时: #include <memory> #include <iostream> // Notice nothing is virtual struct Foo { ~Foo() { std::cout << "Foo\n"; } }; struct Bar : public Foo {
#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
}
}
#包括
#包括
//注意,没有任何东西是虚拟的
结构Foo
{
~Foo(){std::cout这里有一种方法:
{
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
}
{
std::cout void{delete static_cast(p);}
);//打印巴富
}
这种方法的一个主要问题是unique\u ptr
支持转换为逻辑“指向基类的指针”,但该标准并不保证转换到void*
后将产生相同的地址。实际上,这只是一个问题,如果基类是非多态的,而派生类是多态的,则引入vtable ptr,从而可能会稍微更改内存布局。但在这种情况下,这是可能的,但不太可能的删除程序中的强制转换将产生不正确的指针值,并发出砰的一声
因此,就此类转换而言,上述情况在形式上并不安全
要执行与shared_ptr
大致相同的操作(shared_ptr
支持转换为指向基的逻辑指针),您还需要存储原始void*
指针以及删除器
通常,当您控制最顶层的基类时,将其析构函数设置为虚拟
这就解决了所有问题。你应该使Foo
的析构函数成为虚拟的。这是一个很好的实践,不管你是否使用unique\u ptr
。这也会解决你正在处理的问题。unique\u ptr
的deleter是它的类型。如果你使用std::unique_ptr
,然后他们都将使用std::default_delete
。我认为问题在于您的类,而不是std::unique_ptr
。您的析构函数需要是虚拟的。我同意这是应该做的,但在这种情况下,我无法更改类对于有问题的场景,双静态\u cast
-cast如何t先将void*
指向Foo*
,然后再指向Bar*
?@t.C.问题是删除程序不知道传递给void*
的指针类型。根据类型,它可以指向不同的地址。但是现在你让我考虑一下,问题只是void*
放弃It’信息太多了。我想用Foo*
参数类型就可以了,然后在deleter中转换成Bar*
。或者,这有问题吗?对我来说有点晚了。传递到deleter的指针并不总是有用,即使类型是正确的。例如,有时静态转换可能是不可能的我认为唯一真正健壮的解决方案是让删除程序记住原始指针值(从new
返回)。这意味着删除程序正式忽略了它的参数,因此它也可能是无效的。
。最后,一旦您支付了内存“价格”,您还可以添加一个深度拷贝,而无需额外费用。