Выполняйте не более одного явного выделения ресурса в одном выражении-операторе
Причина
Если в одном операторе выполняются два явных выделения ресурсов, возможна утечка, поскольку порядок вычисления многих подвыражений, включая аргументы функций, не определён.
Пример
void fun(shared_ptr<Widget> sp1, shared_ptr<Widget> sp2);
Эту функцию можно вызвать так:
// ПЛОХО: возможна утечка
fun(shared_ptr<Widget>(new Widget(a, b)), shared_ptr<Widget>(new Widget(c, d)));
Это небезопасно при наличии исключений, поскольку компилятор может переупорядочить вычисление двух выражений, строящих аргументы функции. В частности, компилятор может чередовать их выполнение: сначала выделить память (через operator new) для обоих объектов, а затем попытаться вызвать оба конструктора Widget. Если вызов одного из конструкторов выбросит исключение, память второго объекта не будет освобождена!
У этой тонкой проблемы есть простое решение: никогда не выполняйте более одного явного выделения ресурса в одном выражении-операторе. Например:
shared_ptr<Widget> sp1(new Widget(a, b)); // Лучше, но неаккуратно
fun(sp1, new Widget(c, d));
Лучшее решение — полностью отказаться от явного выделения памяти, используя фабричные функции:
fun(make_shared<Widget>(a, b), make_shared<Widget>(c, d)); // Лучший вариант
Напишите собственную фабричную обёртку, если готовой нет.
Контроль
- Отмечать выражения с несколькими явными выделениями ресурсов (проблема: сколько прямых выделений ресурсов мы можем распознать?)