Стандарты программирования на С++. 101 правило и рекомендация | страница 106
Хорошим методом обеспечения освобождения памяти соответствующей функцией является использование >shared_ptr
(см. [C++TR104]). Интеллектуальный указатель >shared_ptr
со счетчиком ссылок может захватить свой "удалитель" в процессе конструирования. "Удалитель" — это функциональный объект (или обычный указатель на функцию), который выполняет освобождение памяти. Поскольку упомянутый функциональный объект, или указатель на функцию, является частью состояния объекта >shared_ptr
, модуль, выделивший память объекту, может одновременно определить функцию освобождения памяти, и эта функция будет корректно вызвана, даже если точка освобождения находится где-то в другом модуле — вероятно, относительно небольшой ценой (корректность важнее цены; см. также рекомендации 5, 6 и 8). Конечно, исходный модуль при этом должен оставаться загруженным.
[С++TR104]
61. Не определяйте в заголовочном файле объекты со связыванием
Объекты со связыванием, включая переменные или функции уровня пространства имен, обладают выделенной для них памятью. Определение таких объектов в заголовочных файлах приводит либо к ошибкам времени компоновки, либо к бесполезному расходу памяти. Помещайте все объекты со связыванием в файлы реализации.
Когда мы начинаем использовать С++, то все достаточно быстро уясняем, что заголовочный файл наподобие
>// Избегайте определения объектов с внешним
>// связыванием в заголовочном файле
>int fudgeFactor;
>string hello("hello, world!");
>void foo() { /* ... */ }
будучи включен больше чем в один исходный файл, ведет при компиляции к ошибкам дублирования символов во время компоновки. Причина проста: каждый исходный файл в действительности определяет и выделяет пространство для >fudgeFactor
, >hello
и тела >foo
, и когда приходит время сборки (компоновки, или связывания), компоновщик сталкивается с наличием нескольких объектов, которые носят одно и то же имя и борются между собой за видимость. Решение проблемы простое — в заголовочный файл надо поместить только объявления:
>extern int fudgeFactor;
>extern string hello;
>void foo(); // В случае объявления функции "extern"
> // является необязательным
Реальные же объявления располагаются в одном файле реализации:
>int fudgeFactor;
>string hello("hello, world!");
>void foo() { /* ... */ }
He определяйте в заголовочном файле и статические объекты уровня пространства имен, например:
>// избегайте определения объектов со статическим
>// связыванием в заголовочном файле