众所周知 ,您可以使用 a来存储指向不完整类型的shared_ptr
指针,只要在构造shared_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
};
[主.cpp]
int main()
{
interface i;
i.foo();
}
[接口.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();
}
这作为“删除对象”shared_ptr
“所有者对象”(*)在in的构造过程中创建pimpl( new impl )
,并在类型擦除后存储在shared_ptr
. 这个“所有者对象”稍后用于销毁指向的对象。这就是为什么提供interface
.
问题:标准在哪里保证它是安全的?
(*) 不是标准的删除器,见下文,但它确实调用自定义删除器或调用删除表达式。该对象通常存储为簿记对象的一部分,应用类型擦除并在虚拟函数中调用自定义删除器/删除表达式。此时,删除表达式也应该是格式正确的。
参考github存储库中的最新草案(94c8fc71,修订N3797),[util.smartptr.shared.const]
template<class Y> explicit shared_ptr(Y* p);
3 要求:
p
应可转换为T*
.Y
应该是一个完整的类型。表达式delete p
应具有良好的格式,应具有明确定义的行为,并且不应引发异常。4 效果:构造一个
shared_ptr
拥有指针的对象p
。5 后置条件:
use_count() == 1 && get() == p
.6 抛出:
bad_alloc
,或当无法获取内存以外的资源时发生实现定义的异常。
注意:对于这个 ctor,shared_ptr
不需要拥有一个 deleter。通过deleter,标准似乎意味着自定义删除器,例如您在构建过程中作为附加参数提供(或shared_ptr
从另一个获取/共享一个shared_ptr
,例如通过复制分配)。另见(另见 [util.smartptr.shared.const]/9)。实现(boost、libstdc++、MSVC,我猜每个理智的实现)总是存储一个“所有者对象”。
由于删除器是自定义删除器,因此如果没有自定义删除器,则 的析构函数shared_ptr
是根据(delete-expression) 定义的:delete
[util.smartptr.shared.dest]
~shared_ptr();
1 效果:
- 如果
*this
为空shared_ptr
或与另一个实例共享所有权(use_count() > 1
),则没有副作用。- 否则,如果
*this
拥有一个对象p
和一个删除器d
,d(p)
则调用。- 否则,
*this
拥有一个指针p
,并被delete p
调用。
我假设意图是需要一个实现来正确删除存储的指针,即使在shared_ptr
dtor 的范围内,delete-expression 格式不正确或会调用 UB。(delete-expression 必须格式正确,并且在 ctor 中具有明确定义的行为。)所以,问题是
问题:这在哪里需要?
(还是我太挑剔了,很明显,实现需要使用“所有者对象”?)