C++ 是否共享ptr';s数据或要求使用;删除者;?
您可以使用C++ 是否共享ptr';s数据或要求使用;删除者;?,c++,c++11,shared-ptr,language-lawyer,C++,C++11,Shared Ptr,Language Lawyer,您可以使用shared\u ptr来存储指向不完整类型的指针,只要在构建shared\u ptr的过程中可以删除该指针(具有定义良好的行为)。例如,PIMPL技术: struct interface { interface(); // out-of-line definition required ~interface() = default; // public inline member, even if implicitly define
shared\u ptr
来存储指向不完整类型的指针,只要在构建shared\u ptr
的过程中可以删除该指针(具有定义良好的行为)。例如,PIMPL技术:
struct interface
{
interface(); // out-of-line definition required
~interface() = default; // public inline member, even if implicitly defined
void foo();
private:
struct impl; // incomplete type
std::shared_ptr<impl> pimpl; // pointer to incomplete type
};
[interface.cpp]
struct interface::impl
{
void foo()
{
std::cout << "woof!\n";
}
};
interface::interface()
: pimpl( new impl ) // `delete impl` is well-formed at this point
{}
void interface::foo()
{
pimpl->foo();
}
3要求:p
应为
可转换为T*
<代码>Y应为完整类型。表达式delete p
应具有良好的结构、明确的行为,且不得
抛出异常
4效果:构造一个拥有
指针p
5个后置条件:使用计数()==1&&get()==p
6抛出:bad\u alloc
,或在
无法获取内存以外的资源
注意:对于此ctor,shared_ptr
不需要拥有删除器。对于删除器,标准似乎是指自定义删除器,例如您在构建过程中作为附加参数提供的删除器(或共享的\u ptr
从另一个共享的\u ptr
,例如通过副本分配)。另请参见(另请参见[util.smartptr.shared.const]/9)。实现(boost、libstdc++、MSVC,我猜每个sane实现)总是存储一个“所有者对象”
由于删除器是自定义删除器,shared_ptr
的析构函数是根据delete
(删除表达式)定义的,如果没有自定义删除器:
[util.smartptr.shared.dest]
1影响:
- 如果
为空或与共享所有权 另一个*此
实例(shared\u ptr
),没有边 效果use\u count()>1
- 否则,如果该
*拥有一个对象
和一个删除者p
,d
被称为d(p)
- 否则,
拥有一个指针*此
,并且p
是 打电话来delete p
shared\u ptr
dtor的范围内,delete表达式格式错误或将调用UB,也需要一个实现来正确删除存储的指针。(delete表达式必须格式良好,并且在ctor中具有定义良好的行为。)因此,问题是
问题:哪里需要这个?
(或者我是不是太挑剔了,而且很明显实现需要使用“所有者对象”?)
问题:哪里需要这个?
如果不需要,析构函数将具有未定义的行为,并且标准没有要求未定义行为的习惯:-)
如果满足构造函数的先决条件,则析构函数将不会调用未定义的行为。实现如何确保这一点尚未明确,但您可以假设它是正确的,您不需要知道如何确保。如果不希望实现做正确的事情,那么析构函数将有一个先决条件
(或者我是不是太挑剔了,而且很明显实现需要使用“所有者对象”?)
是的,必须创建一些额外的对象来拥有指针,因为引用计数(或其他簿记数据)必须在堆上,而不是任何特定共享\u ptr
实例的一部分,因为它可能需要超出任何特定实例。是的,有一个额外的对象,它拥有指针,你可以称之为所有者对象。如果用户没有提供删除器,那么所有者对象只调用delete
。例如:
template<typename T>
struct SpOwner {
long count;
long weak_count;
T* ptr;
virtual void dispose() { delete ptr; }
// ...
};
template<typename T, typename Del>
struct SpOwnerWithDeleter : SpOwner<T> {
Del del;
virtual void dispose() { del(this->ptr); }
// ...
};
模板
结构所有者{
长计数;
长弱_计数;
T*ptr;
虚拟void dispose(){delete ptr;}
// ...
};
模板
结构SpOwnerWithDeleter:SpOwner{
德尔德尔;
虚拟void dispose(){del(this->ptr);}
// ...
};
现在一个
shared\u ptr
有一个SpOwner*
,当计数降到零时,它调用虚拟函数dispose()
,该函数调用delete
或调用deleter,具体取决于对象的构造方式。当构建共享的ptr
时,决定是构建SpOwner
还是构建SpOwnerWithDeleter
,并且当共享的ptr
被销毁时,该类型仍然相同,因此,如果它需要处理所拥有的指针,那么它将做正确的事情。SpOwner
是一个deleter对象,因为它定义了删除策略。它不同于作为参数传递的deleter,因为它不是函子。”然后键入拥有指针的已擦除对象,只调用delete“这就是我所说的“deleter对象”。在libstdc++中:\u Sp\u counted\u ptr
存储在\u shared\u count
中的\u shared\u ptr
中(作为指针存储在堆上),该对象由shared\u ptr
派生而来。但它不是get\u deleter
返回的,因此它不是shared\u ptr
使用的“deleter对象”。我用引号引这些词是有原因的。owner对象不“存储删除器对象”(正如您在问题中所说的那样),而是自行删除。我更改了问题中的术语,也许现在更清楚了?好吧,那么您的问题基本上是“是否有什么东西负责安全地删除指针?”答案是“是的,当然”:-)但不需要指定如何完成。必须创建一些其他对象来存储堆上的引用计数,因为它们不能在任何单个共享\u ptr
对象中,并且当指针的动态类型已知时,该其他对象必须由构造函数创建,以便它(或它创建的对象)知道如何安全地删除指针。实现者必须非常不称职才能不这样做
template<class Y> explicit shared_ptr(Y* p);
~shared_ptr();
template<typename T>
struct SpOwner {
long count;
long weak_count;
T* ptr;
virtual void dispose() { delete ptr; }
// ...
};
template<typename T, typename Del>
struct SpOwnerWithDeleter : SpOwner<T> {
Del del;
virtual void dispose() { del(this->ptr); }
// ...
};