Как объединить std::make_shared и new(std::nothrow)

В новой версии C++ есть возможность возвращать нулевой указатель, а не выдавать исключение bad_alloc в случае неудачного размещения.

Foo * pf = new(std::nothrow) Foo(1, 2, 3);

(Да, я понимаю, что это только препятствует тому, чтобы новый бросал bad_alloc; это не мешает конструктору Foo генерировать исключение.)

Если вы хотите использовать совместно используемый указатель вместо необработанного указателя, вы, как правило, должны использовать make_shared, так как он хорошо разбирается в распределении блока управления.

auto pf = std::make_shared<Foo>(1, 2, 3);

make_shared инкапсулирует новое, что делает невозможным (?) выбрать версию nothrow. Похоже, вам нужно отказаться от make_shared и явно вызывать new.

std::shared_ptr<Foo> pf(new(std::nothrow) Foo(1, 2, 3));

Это исключает оптимизацию выделения блока управления с помощью Foo, и выделение блока управления может завершиться неудачей независимо от распределения Foo, но я не хочу на этом фокусироваться. Давайте предположим, что блок управления мал, поэтому его распределение никогда не будет неудачным на практике. Меня беспокоит неспособность выделить место для Foo.

Есть ли способ получить преимущество make_shared для одиночного размещения при сохранении возможности просто получить нулевой указатель вместо исключения bad_alloc при выделении пространства для Foo?

2 ответа

Решение

Это выглядит как allocate_shared, передавая распределитель, который использует nothrow новый должен сделать свое дело для вас.

Просто создайте собственный nake_foo и поймайте исключение:

#include <memory>

struct Foo {
    Foo(int, int, int) { throw std::bad_alloc(); }
};

std::shared_ptr<Foo> make_foo(int a, int b, int c) {
    try { return std::make_shared<Foo>(a, b, c); }
    catch (const std::bad_alloc&) { return std::shared_ptr<Foo>(); }
}
Другие вопросы по тегам