Стандарты программирования на С++. 101 правило и рекомендация | страница 111



Требуется найти определенный компромисс между проблемами используемых типов, которые могут не быть корректно восприняты всеми клиентами, и проблемами использования низкого уровня абстракции. Абстракция важна; если некоторые клиенты понимают только низкоуровневые типы и вы ограничены в использовании этими типами, то, возможно, следует подумать о дополнительных операциях, работающих с высокоуровневыми типами. Рассмотрим функцию >SummarizeFile, которая получает в качестве аргумента файл. Имеется три варианта действий — передать указатель >char* на строку в стиле С с именем файла; передать >string с именем файла и передать объект >istream или пользовательский объект >Filе. Каждый из этих вариантов представляет свой уровень компромисса.

• Вариант 1. >char*. Очевидно, что тип >char* доступен наиболее широкому кругу клиентов. К сожалению, это также наиболее низкоуровневый вариант; в частности, он более проблематичен (например, вызывающий и вызываемый код должны явно решить, кто именно выделяет память для строки и кто ее освобождает), более подвержен ошибкам (например, файл может не существовать), и менее безопасен (например, может оказаться подвержен классической атаке, основанной на переполнении буфера).

• Вариант 2. >string. Тип >string доступен меньшему кругу клиентов, ограниченному использованием С++ и компиляцией с использованием той же реализации стандартной библиотеки, того же компилятора и совместимых настроек компилятора. Взамен мы получаем менее проблематичный (надо меньше беспокоиться об управлении памятью; однако см. рекомендацию 60) и более безопасный код (например, тип >string увеличивает при необходимости свой буфер и не так подвержен атакам на основе переполнения буфера). Но и этот вариант относительно низкоуровневый, а потому так же открытый для ошибок, как и предыдущий (например, указанный файл может и не существовать).

• Вариант 3. >istream или >File. Если уж вы переходите к типам, являющимся классами, т.е. в любом случае требуется, чтобы клиент использовал язык программирования С++, причем тот же компилятор с теми же опциями компиляции, то воспользуйтесь преимуществами абстракции: класс >istream (или пользовательский класс >File, представляющий собой оболочку вокруг >istream, позволяющую устранить зависимость от реализации стандартной библиотеки) повышает уровень абстракции и делает API существенно менее проблематичным. Функция получает объект типа >File или соответствующий входной поток, она не должна заботиться об управлении памятью для строк, содержащих имя файла, и защищена от множества ошибок, которые вполне возможны при использовании первых двух вариантов. Остается только выполнить несколько проверок: файл должен быть открыт, а его содержимое иметь верный формат, но, в принципе, этим и ограничивается список неприятностей, которые могут произойти в данном варианте.