Pat*_*ick 20 c++ smart-pointers shared-ptr visual-c++ c++11
为了解决我的应用程序中一个非常特殊的问题,我需要一个指向已分配数据的共享指针,但对于外部世界,底层数据类型应保持隐藏状态.
我可以通过创建我的其他所有类继承的某种Root类来解决这个问题,并在此Root类上使用shared_ptr,如下所示:
std::shared_ptr<Root>
Run Code Online (Sandbox Code Playgroud)
然而:
奇怪的是,似乎你可以在void上创建一个shared_ptr,这似乎工作正常,如下例所示:
class X
{
public:
X() {std::cout << "X::ctor" << std::endl;}
virtual ~X() {std::cout << "X::dtor" << std::endl;}
};
typedef std::shared_ptr<void> SharedVoidPointer;
int main()
{
X *x = new X();
SharedVoidPointer sp1(x);
}
Run Code Online (Sandbox Code Playgroud)
x被正确删除,在一个更大的实验中,我可以验证共享指针确实完成了它需要做的事情(删除x,最后一个shared_ptr结束了灯光).
当然,这解决了我的问题,因为我现在可以使用SharedVoidPointer数据成员返回数据,并确保它正确地清理它应该在哪里.
但这是否可以保证在所有情况下都有效?它显然适用于Visual Studio 2010,但这是否也可以在其他编译器上正常工作?在其他平台上?
Jam*_*lis 27
在shared_ptr您使用的构造函数实际上是一个构造函数模板,看起来像:
template <typename U>
shared_ptr(U* p) { }
Run Code Online (Sandbox Code Playgroud)
它知道构造函数内部指针的实际类型是什么(X)并使用此信息来创建一个能够正确delete指向指针并确保调用正确析构函数的仿函数.这个仿函数(称为shared_ptr"删除者")通常与用于维护对象共享所有权的引用计数一起存储.
请注意,这仅在将正确类型的指针传递给shared_ptr构造函数时才有效.如果你反而说:
SharedVoidPointer sp1(static_cast<void*>(x));
Run Code Online (Sandbox Code Playgroud)
那么这不会有效,因为在构造函数模板U中void,不是X.然后行为将是未定义的,因为不允许delete使用void指针调用.
一般来说,如果你总是调用new构造a shared_ptr并且不将对象(the new)的创建与获取对象的所有权(创建shared_ptr)分开,那么你是安全的.
nob*_*bar 10
我认为问题的隐含点是你不能删除void*,所以你可以通过删除看起来很奇怪shared_ptr<void>.
您不能通过raw删除对象void*主要是因为它不知道要调用的析构函数.使用虚拟析构函数没有帮助,因为void没有vtable(因此没有虚拟析构函数).
James McNellis清楚地解释了为什么shared_ptr<void>有效,但这里有一些有趣的东西: 假设您遵循记录的最佳实践,在调用时始终使用以下形式new...
shared_ptr<T> p(new Y);
Run Code Online (Sandbox Code Playgroud)
... 使用shared_ptr时没有必要使用虚拟析构函数.无论T是void,还是在更熟悉的情况下,T是Y的多态基.
这违背了长期的传统观念:接口类必须具有虚拟析构函数.
由于delete (void*)shared_ptr构造函数是一个记住它需要破坏的数据类型的模板,因此解决了OP的问题.该机制以完全相同的方式解决了虚拟析构函数问题.
因此,即使对象的实际类型不一定是以shared_ptr本身的类型捕获的(因为T不必与Y的类型相同),但是,shared_ptr会记住它所持有的对象类型并执行当删除对象时,转换为该类型(或执行与此类似的操作).
| 归档时间: |
|
| 查看次数: |
8222 次 |
| 最近记录: |