Подтвердить что ты не робот

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

С++ new имеет возможность возвращать нулевой указатель вместо того, чтобы бросать исключение 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 и явно вызвать ящик.

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

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

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

4b9b3361

Ответ 1

Похоже на allocate_shared, передача в распределителе, который использует nothrow new, должен сделать трюк для вас.

Ответ 2

Просто создайте пользовательский 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>(); }
}