gpt4 book ai didi

c++ - shared_ptr 的 dtor 是否需要使用 "deleter"?

转载 作者:可可西里 更新时间:2023-11-01 18:37:51 24 4
gpt4 key购买 nike

It's widely known您可以使用 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
};

[ main.cpp ]

int main()
{
interface i;
i.foo();
}

[接口(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();
}

这作为 “删除对象” “所有者对象”(*) 在 pimpl( new impl )shared_ptr 的构造过程中创建,并在类型删除后存储在 shared_ptr 中。这个“所有者对象”稍后用于销毁指向的对象。这就是为什么提供 interface内联析构函数应该是安全的。

问题:标准在何处保证其安全?

(*) 不是标准中的删除器,见下文,但它调用自定义删除器或调用 delete-expression。该对象通常存储为簿记对象的一部分,应用类型删除并在虚函数中调用自定义删除器/删除表达式。此时,delete-expression 也应该是合式的。


引用github仓库中的最新草案(94c8fc71,修订N3797),[util.smartptr.shared.const]

template<class Y> explicit shared_ptr(Y* p);

3    Requires: p shall be convertible to T*. Y shall be a complete type. The expression delete p shall be well formed, shall have well defined behavior, and shall not throw exceptions.

4    Effects: Constructs a shared_ptr object that owns the pointer p.

5    Postconditions: use_count() == 1 && get() == p.

6    Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.

注意:对于这个 ctor,shared_ptr 不需要拥有删除器。对于deleter,标准似乎意味着自定义删除器,例如您在构造期间作为附加参数提供(或 shared_ptr 获取/共享一个来自另一个 shared_ptr,例如通过复制分配)。另请参阅(另请参阅 [util.smartptr.shared.const]/9)。实现(boost、libstdc++、MSVC,我想每个理智的实现)总是存储一个“所有者对象”。

由于删除器是一个自定义删除器shared_ptr 的析构函数是根据delete ( delete-expression) 如果没有自定义删除器:

[util.smartptr.shared.dest]

~shared_ptr();

1    Effects:

  • If *this is empty or shares ownership with another shared_ptr instance (use_count() > 1), there are no side effects.
  • Otherwise, if *this owns an object p and a deleter d, d(p) is called.
  • Otherwise, *this owns a pointer p, and delete p is called.

我假设意图是需要一个实现来正确删除存储的指针,即使在shared_ptr dtor 的范围内,delete-expression 是格式错误或会调用 UB。 (delete-expression 必须格式正确并且在构造函数中具有明确定义的行为。)所以,问题是

问题:这是哪里要求的?

(或者我是不是太挑剔了,很明显,实现需要使用“所有者对象”?)

最佳答案

Question: Where is this required?

如果不需要,析构函数将具有未定义的行为,并且标准不习惯要求未定义的行为:-)

如果满足构造函数的前提条件,那么析构函数将不会调用未定义的行为。实现如何确保未指定,但您可以假设它是正确的,并且您不需要知道如何做到这一点。如果不期望实现做正确的事,那么析构函数将有一个先决条件。

(Or am I just too nit-picky and it's obvious somehow that the implementations are required to use a "owner object"?)

是的,必须创建一些额外的对象来拥有指针,因为引用计数(或其他簿记数据)必须在堆上而不是任何特定 shared_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); }
// ...
};

现在 shared_ptr 有一个 SpOwner* 并且当计数下降到零时它调用虚函数 dispose() 调用 delete 或调用删除器,具体取决于对象的构造方式。是构造SpOwner还是构造SpOwnerWithDeleter的决定是在构造shared_ptr时做出的,并且当shared_ptr 被销毁,因此如果它需要处理拥有的指针,那么它将做正确的事。

关于c++ - shared_ptr 的 dtor 是否需要使用 "deleter"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19846444/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com