Требует ли dtor для shared_ptr использования «удалителя»?

Это широко известен что вы можете использовать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();
}

Это работает как"объект удаления" «Объект-владелец» (*) создается во время строительстваshared_ptr в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Стандарт, кажется, означаетпользовательский удалительтакие, как вы предоставляете во время построения в качестве дополнительного параметра (илиshared_ptr приобретает / делится один от другогоshared_ptrнапример, через копирование-назначение). Также см. (Также см. [Util.smartptr.shared.const] / 9). Реализации (boost, libstdc ++, MSVC и, я думаю, каждая нормальная реализация) всегда хранят «объект-владелец».

КакDeleter этопользовательский удалительДеструкторshared_ptr определяется с точки зренияdelete (delete-expression), если пользовательского удалителя нет:

[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 неправильно сформировано или вызовет UB. (Выражение delete должно быть правильно сформировано и иметь четкое поведение в ctor.) Итак, вопрос в том,

Вопрос: Где это требуется?

(Или я просто слишком придирчив, и как-то очевидно, что реализации должны использовать «объект-владелец»?)

Ответы на вопрос(1)

Ваш ответ на вопрос