c – shared_ptr的dtor是否需要使用“删除器”?

前端之家收集整理的这篇文章主要介绍了c – shared_ptr的dtor是否需要使用“删除器”?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
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中的类型擦除之后存储.此“所有者对象”稍后用于销毁指向的对象.这就是为什么提供接口的内联析构函数应该是安全的.

问题:标准在哪里保证它是安全的?

(*)就标准而言,不是删除器,见下文,但它可以调用自定义删除器或调用delete-expression.该对象通常作为簿记对象的一部分存储,应用类型擦除并在虚函数调用自定义删除/删除表达式.此时,delete-expression也应该是格式良好的.

参考github存储库中的最新草案(94c8fc71,修改N3797),[util.smartptr.shared.const]

06003

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不需要拥有删除器.通过删除,标准似乎意味着自定义删除,例如您在构造期间提供的附加参数(或shared_ptr从另一个shared_ptr获取/共享一个,例如通过复制分配).另见(另见[util.smartptr.shared.const] / 9).实现(boost,libstdc,MSVC,我猜每个理智的实现)总是存储“所有者对象”.

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

[util.smartptr.shared.dest]

06004

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必须格式正确并且在ctor中具有明确定义的行为.)所以,问题是

问题:这需要在哪里?

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

解决方法

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被销毁时该类型仍然相同,因此如果它需要处理拥有的指针,那么它将执行正确的操作.

原文链接:https://www.f2er.com/c/119149.html

猜你在找的C&C++相关文章