int &r4 = 42; //
//
Те же правила инициализации относятся и к передаче параметров:
int i = 0;
const int ci = i;
string::size_type ctr = 0;
reset(&i); //
reset(&ci); //
//
reset(i); //
reset(ci); //
//
reset(42); //
reset(ctr); //
//
find_char("Hello World!", 'o', ctr);
Ссылочную версию функции reset()
(см. раздел 6.2.2) можно вызвать только для объектов типа int
. Нельзя передать литерал, выражение, результат которого будет иметь тип int
, объект, который требует преобразования, или объект типа const int
. Точно так же версии функции reset()
с указателем можно передать только объект типа int*
(см. раздел 6.2.1). С другой стороны, можно передать строковый литерал как первый аргумент функции find_char()
(см. раздел 6.2.2). Ссылочный параметр этой функции — ссылка на константу, и можно инициализировать ссылки на константу из литералов.
Весьма распространена ошибка, когда не изменяемые функцией параметры определяют как простые ссылки. Это создает у вызывающей стороны функции ложное впечатление, что функция могла бы изменить значение своего аргумента. Кроме того, использование ссылки вместо ссылки на константу неоправданно ограничивает типы аргументов, применяемые функцией. Как уже упоминалось, нельзя передать константный объект, литерал или требующий преобразования объект как простой ссылочный параметр.
В качестве примера рассмотрим функцию find_char()
из раздела 6.2.2. Строковый параметр этой функции правильно сделан ссылкой на константу. Если бы этот параметр был определен как string&
:
//
string::size_type find_char(string &s, char c,
string::size_type &occurs);
то вызвать ее можно было бы только для объекта класса string
, так что
find_char("Hello World", 'o', ctr);
привело бы к неудаче во времени компиляции.
Более того, эту версию функции find_char()
нельзя использовать из других функций, которые правильно определяют свои параметры как ссылки на константу. Например, мы могли бы использовать функцию find_char()
в функции, которая определяет, является ли строка предложением:
bool is_sentence(const string &s) {
//
string::size_type ctr = 0;
return find_char(s, ctr) == s.size() - 1 && ctr == 1;
}
Если бы функция find_char()
получала простую ссылку string?
, то этот ее вызов привел бы к ошибке при компиляции. Проблема в том, что s
— ссылка на const string
, но функция find_char()
была неправильно определена как получающая простую ссылку.
Было бы заманчиво попытаться исправить эту проблему, изменив тип параметра в функции is_sentence()
. Но это только распространит ошибку, так как вызывающая сторона функции is_sentence()
сможет передавать только неконстантные строки.
Правильный способ решения этой проблемы — исправить параметр функции find_char()
. Если невозможно изменить функцию find_char()
, определите локальную копию строки s
в функции is_sentence()
и передавайте эту строку функции find_char()
.
Упражнение 6.16. Несмотря на то что следующая функция допустима, она менее полезна, чем могла бы быть. Выявите и исправьте ограничение этой функции:
bool is_empty(string& s) { return s.empty(); }