Чтение онлайн

на главную

Жанры

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

Александреску Андрей

Шрифт:

• Они практически не снижают эффективность ваших программ. В классах

vector
и
string
при выборе между эффективностью и безопасностью решение принимается в пользу эффективности (естественно, не в отладочном режиме). Тем не менее, стандартные средства оказываются гораздо лучшей платформой для создания безопасных компонентов, чем обычные массивы и указатели.

• Они стимулируют оптимизацию. Современные реализации стандартной библиотеки включают оптимизации, о которых многие из нас просто никогда бы и не подумали.

Применение массива может быть оправданно, когда его размер фиксирован на стадии

компиляции (например,
float[3]
для трехмерной точки; переход к четвертому измерению все равно потребует перепроектирования программы).

Ссылки

[Alexandrescu01а] • [Dewhurst03] §13, §60, §68 • [Meyers01] §13, §16 • [Stroustrup00] §3.5-7, §5.3, §20.4.1, §C.7 • [Sutter00] §36

78. Используйте

vector
string::c_str
) для обмена данными с API на других языках

Резюме

vector
и
string::c_str
служат шлюзом для сообщения с API на других языках. Однако не полагайтесь на то, что итераторы являются указателями; для получения адреса элемента, на который ссылается
vector<T>::iterator iter
, используйте выражение
&*iter
.

Обсуждение

vector
(в первую очередь) и
string::c_str
и
string::data
(во вторую) представляют собой наилучшие способы обмена данными с API на других языках вообще и с библиотеками на С в частности.

Данные

vector
всегда хранятся последовательно, так что получение адреса первого элемента вектора дает указатель на его содержимое. Используйте
&*v.begin
,
&v[0]
или
&v.front
для получения указателя на первый элемент
v
. Для получения указателя на n-й элемент вектора лучше сначала провести арифметические вычисления, а затем получить адрес (например,
&v.begin[n]
или
&v[n]
) вместо получения указателя на начало данных с последующим применением арифметики указателей (например,
(&v.front)[n]
). Это связано с тем, что в первом случае в отладочной реализации выполняется проверка на доступ к элементу за пределами
v
(см. рекомендацию 83).

Нельзя полагаться на то, что

v.begin
возвращает указатель на первый элемент или, в общем случае, что итераторы вектора являются указателями. Хотя некоторые реализации STL определяют
vector<T>::iterator
как обычный указатель
T*
, итераторы могут быть (и все чаще так оно и есть) полноценными типами (еще раз см. рекомендацию 83).

Хотя в большинстве реализаций для

string
также используется непрерывный блок памяти, это не гарантируется стандартом, так что никогда не используйте адрес символа в строке, считая его указателем на все содержимое строки. Хорошая новость заключается в том, что функция
string::c_str
всегда возвращает строку в стиле С с завершающим нулевым символом (
string::data
также возвращает указатель на непрерывный блок памяти, но не гарантирует наличия завершающего нулевого символа).

Когда вы передаете указатель на данные объекта

v
типа
vector
, код на языке С может как читать, так и записывать элементы
v
; однако он не должен выходить за
границы данных. Хорошо продуманный API на языке С должен получать наряду с указателем либо максимальное количество объектов (до
v.size
), либо указатель на элемент, следующий за последним (
&*v.begin+v.size
).

Если у вас есть контейнер объектов типа

T
, отличный от
vector
или
string
, и вы хотите передать его содержимое (или заполнить его) функции API на другом языке программирования, которая ожидает указатель на массив объектов типа
T
, скопируйте содержимое контейнера в (или из)
vector<T>
, который может непосредственно сообщаться с такими функциями.

Ссылки

[Josuttis99] §6.2.3, §11.2.4 • [Meyers01] §16 • [Musser01] §B • [Stroustrup00] §16.3.1

79. Храните в контейнерах только значения или интеллектуальные указатели

Резюме

Храните к контейнерах объекты-значения. Контейнеры полагают, что их содержимое имеет тип значения, включая непосредственно хранящиеся значения, интеллектуальные указатели и итераторы.

Обсуждение

Наиболее распространенное использование контейнеров — для непосредственного хранения значений (например,

vector<int>, set<string>
). В случае контейнеров указателей, если контейнер владеет объектами, на которые указывает, то лучше использовать контейнер интеллектуальных указателей со счетчиком ссылок (например,
list<shared_ptr<Widget> >
); в противном случае можно выбрать контейнер обычных указателей (например,
list<Widget*>
) или иных значений, подобных указателям — таких как итераторы (например,
list<vector<Widget>::iterator>
).

Примеры

Пример 1.

auto_ptr
. Объекты
auto_ptr<T>
не являются объектами-значениями из-за своей семантики передачи владения при копировании. Использование контейнера объектов
auto_ptr
(например,
vector<auto_ptr<int> >
) должно привести к ошибке компиляции. Но даже в случае успешной компиляции никогда не пишите такой код — вместо этого вам следует использовать контейнер интеллектуальных указателей
shared_ptr
.

Пример 2. Гетерогенные контейнеры. Для того чтобы получить контейнер, хранящий и владеющий объектами различных, но связанных типов, например, типов, производных от общего базового класса, лучше использовать

container<shared_ptr<Base> >
. Альтернативой является хранение прокси-объектов, невиртуальные функции которых передают вызовы соответствующим виртуальным функциям реальных объектов.

Пример 3. Контейнеры типов, не являющихся значениями. Для того чтобы хранить объекты, несмотря на невозможность их копирования или другое их поведение, делающее их типами, не являющимися значениями (например,

DatabaseLock
или
TcpConnection
), их следует хранить опосредованно, с использованием интеллектуальных указателей (например,
container<shared_ptr<DatabaseLock> >
или
container<shared_ptr<TcpConnection> >
).

Поделиться:
Популярные книги

Свадьба по приказу, или Моя непокорная княжна

Чернованова Валерия Михайловна
Любовные романы:
любовно-фантастические романы
5.57
рейтинг книги
Свадьба по приказу, или Моя непокорная княжна

Сборник коротких эротических рассказов

Коллектив авторов
Любовные романы:
эро литература
love action
7.25
рейтинг книги
Сборник коротких эротических рассказов

Отец моего жениха

Салах Алайна
Любовные романы:
современные любовные романы
7.79
рейтинг книги
Отец моего жениха

Вадбольский

Никитин Юрий Александрович
1. Вадбольский
Фантастика:
попаданцы
5.00
рейтинг книги
Вадбольский

Бастард Императора. Том 7

Орлов Андрей Юрьевич
7. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 7

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

В зоне особого внимания

Иванов Дмитрий
12. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
В зоне особого внимания

Таня Гроттер и магический контрабас

Емец Дмитрий Александрович
1. Таня Гроттер
Фантастика:
фэнтези
8.52
рейтинг книги
Таня Гроттер и магический контрабас

Бастард Императора. Том 2

Орлов Андрей Юрьевич
2. Бастард Императора
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бастард Императора. Том 2

Кодекс Крови. Книга ХI

Борзых М.
11. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХI

Третий

INDIGO
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий

Возвышение Меркурия. Книга 16

Кронос Александр
16. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 16

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9

Потусторонний. Книга 1

Погуляй Юрий Александрович
1. Господин Артемьев
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Потусторонний. Книга 1