Не передавайте указатель или ссылку, полученные из псевдонима умного указателя
Причина
Нарушение этого правила является главной причиной потери счётчика ссылок и возникновения висячих указателей. Функции должны предпочитать передавать сырые указатели и ссылки по цепочке вызовов. На вершине дерева вызовов, где вы получаете сырой указатель или ссылку из умного указателя, удерживающего объект живым, нужно убедиться, что умный указатель не может быть случайно сброшен или переприсвоен внутри дерева вызовов ниже.
Примечание
Иногда для этого нужно взять локальную копию умного указателя, которая гарантирует, что объект живёт на протяжении всей функции и дерева вызовов.
Пример
Рассмотрим следующий код:
// глобальный (статический или в куче) или псевдоним локального ...
shared_ptr<widget> g_p = ...;
void f(widget& w)
{
g();
use(w); // A
}
void g()
{
g_p = ...; // ой, если это был последний shared_ptr на widget — уничтожает widget
}
Следующее не должно пройти код-ревью:
void my_code()
{
// ПЛОХО: передаётся указатель или ссылка, полученные из нелокального умного указателя,
// который может быть случайно сброшен внутри f или её вызываемых функций
f(*g_p);
// ПЛОХО: та же причина, просто передаётся как указатель this
g_p->func();
}
Исправление простое — возьмите локальную копию указателя:
void my_code()
{
// дёшево: 1 инкремент покрывает всю эту функцию и все деревья вызовов ниже
auto pin = g_p;
// ХОРОШО: передаётся указатель или ссылка из локального умного указателя
f(*pin);
// ХОРОШО: та же причина
pin->func();
}
Контроль
- (Простой) Предупреждать, если указатель или ссылка, полученные из переменной умного указателя (
Unique_pointerилиShared_pointer), нелокальной или локальной, но потенциально являющейся псевдонимом, используются в вызове функции. Если умный указатель —Shared_pointer, предлагать взять локальную копию умного указателя и получить из неё указатель или ссылку.
ES: Выражения и операторы
Выражения и операторы — это наиболее низкоуровневый и прямой способ выражения действий и вычислений. Объявления в локальных областях видимости являются операторами.
Правила именования, комментирования и отступов смотрите в NL: Именование и оформление.
Общие правила:
- ES.1: Предпочитайте стандартную библиотеку другим библиотекам и «ручному коду»
- ES.2: Предпочитайте подходящие абстракции прямому использованию возможностей языка
- ES.3: Не повторяйтесь, избегайте избыточного кода
Правила объявлений:
- ES.5: Делайте области видимости небольшими
- ES.6: Объявляйте имена в инициализаторах и условиях for-операторов, чтобы ограничить область видимости
- ES.7: Делайте распространённые и локальные имена короткими, а редкие и нелокальные — длиннее
- ES.8: Избегайте похожих имён
- ES.9: Избегайте имён
ALL_CAPS - ES.10: Объявляйте только одно имя в объявлении
- ES.11: Используйте
auto, чтобы избежать лишнего повторения имён типов - ES.12: Не переиспользуйте имена во вложенных областях видимости
- ES.20: Всегда инициализируйте объект
- ES.21: Не вводите переменную (или константу) до того, как она вам понадобится
- ES.22: Не объявляйте переменную, пока не знаете, чем её инициализировать
- ES.23: Предпочитайте синтаксис инициализатора
{} - ES.24: Используйте
unique_ptr<T>для хранения указателей - ES.25: Объявляйте объект
constилиconstexpr, если не планируете изменять его значение позже - ES.26: Не используйте одну переменную для двух не связанных целей
- ES.27: Используйте
std::arrayилиstack_arrayдля массивов на стеке - ES.28: Используйте лямбды для сложной инициализации, особенно
const-переменных - ES.30: Не используйте макросы для манипуляций с текстом программы
- ES.31: Не используйте макросы для констант или «функций»
- ES.32: Используйте
ALL_CAPSдля всех имён макросов - ES.33: Если вы вынуждены использовать макросы, давайте им уникальные имена
- ES.34: Не определяйте (C-стиля) функции с переменным числом аргументов
Правила для выражений:
- ES.40: Избегайте сложных выражений
- ES.41: При сомнении в приоритете операторов — используйте скобки
- ES.42: Используйте указатели просто и понятно
- ES.43: Избегайте выражений с неопределённым порядком вычисления
- ES.44: Не полагайтесь на порядок вычисления аргументов функции
- ES.45: Избегайте «магических констант»; используйте символические константы
- ES.46: Избегайте сужающих преобразований
- ES.47: Используйте
nullptrвместо0илиNULL - ES.48: Избегайте приведений типов
- ES.49: Если приведение необходимо — используйте именованное
- ES.50: Не снимайте
const - ES.55: Избегайте необходимости проверки диапазонов
- ES.56: Пишите
std::move()только когда нужно явно переместить объект в другую область видимости - ES.60: Избегайте
newиdeleteвне функций управления ресурсами - [ES.61: Удаляйте массивы через
delete[], а не массивы — черезdelete](/roadmap/cpp/guidelines/es-61) - ES.62: Не сравнивайте указатели на разные массивы
- ES.63: Не нарезайте
- ES.64: Используйте нотацию
T{e}для конструирования - ES.65: Не разыменовывайте недействительный указатель
Правила для операторов:
- ES.70: Предпочитайте
switchоператоруif, когда есть выбор - ES.71: Предпочитайте
forс диапазоном обычномуfor, когда есть выбор - ES.72: Предпочитайте
forоператоруwhile, когда переменная цикла очевидна - ES.73: Предпочитайте
whileоператоруfor, когда переменная цикла не очевидна - ES.74: Предпочитайте объявлять переменную цикла в части инициализации
for - ES.75: Избегайте
do-операторов - ES.76: Избегайте
goto - ES.77: Минимизируйте использование
breakиcontinueв циклах - ES.78: Не полагайтесь на неявный проваливатель в операторах
switch - ES.79: Используйте
defaultтолько для общих случаев - ES.84: Не пытайтесь объявить локальную переменную без имени
- ES.85: Делайте пустые операторы видимыми
- ES.86: Избегайте изменения переменных управления циклом внутри тела цикла
for - ES.87: Не добавляйте избыточные
==или!=в условия
Правила для арифметики:
- ES.100: Не смешивайте знаковую и беззнаковую арифметику
- ES.101: Используйте беззнаковые типы для битовых операций
- ES.102: Используйте знаковые типы для арифметики
- ES.103: Не допускайте переполнения
- ES.104: Не допускайте потери значения снизу
- ES.105: Не делите на целочисленный ноль
- ES.106: Не пытайтесь избежать отрицательных значений с помощью
unsigned - ES.107: Не используйте
unsignedдля индексов; предпочитайтеgsl::index