Стандарты программирования на С++. 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 определяйте в заголовочном файле и статические объекты уровня пространства имен, например:

>// избегайте определения объектов со статическим

>// связыванием в заголовочном файле