Если вы хотите избежать new
, главным образом, чтобы избежать дополнительного кода очистки и потенциальных ошибок от висячих указателей, двойных удалений и т. Д. c., Просто используйте std::unique_ptr
:
std::unique_ptr<A> o1;
if (cond)
o1 = std::make_unique<B>();
else
o1 = std::make_unique<C>();
o1->p();
This будет делать то же самое, что и код, использующий new
, но за кадром, а также delete
для вас, когда o1
выходит за рамки.
Если у вас есть код, критичный для производительности Узкое место и желание избежать накладных расходов на выделение и освобождение кучи памяти, используемых new
, все усложняется, но вы можете сделать это с помощью чего-то вроде:
using B_or_C_type = std::variant<B,C>;
auto o5 = cond ? B_or_C_type{B{}} : B_or_C_type{C{}};;
std::visit(std::mem_fn(&A::p), o5);
В типичных системах этот код позволит избежать использовать любую память кучи вообще, вместо этого используя стековую память, достаточно большую, чтобы вместить большее из B или C. У std::variant
есть логика c, действующая как union
, но проверяющая, что на самом деле используется только правильный тип. std::visit
применяет любой функтор к варианту при условии, что функтор может быть вызван с каждым типом в варианте. Обратите внимание, что если вы определяете переменную variant
без инициализатора, он создает объект первого типа, хотя позже его можно переназначить объекту другого типа. (Если создание этого объекта по умолчанию невозможно или его следует избегать, вы можете использовать std::monostate
в качестве первого фиктивного типа - но затем использование std::visit
становится сложнее.)