Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 35

Скотт Мейерс

С учетом этой информации посмотрим еще раз на следующую часть исходного кода:

bool highPriority = features(w)[5]; // Явное объявление типа

                                    // highPriority

Здесь features возвращает объект std::vector<bool>, для которого вызывается operator[]. Этот оператор возвращает объект типа std::vector<bool>::reference, который затем неявно преобразуется в значение типа bool, необходимое для инициализации highPriority. Таким образом, highPriority в конечном итоге получает значение пятого бита из std::vector<bool>, возвращенного функцией features, так, как и предполагалось.

Но что же произойдет, если переменная highPriority будет объявлена как auto?

auto highPriority = features(w)[5]; // Вывод типа highPriority

Функция features, как и ранее, возвращает объект типа std::vector<bool>, и, как и ранее, выполняется его operator[]. Оператор возвращает объект типа std::vector<bool>::reference, но дальше привычный ход событий изменяется, так как auto приводит к выводу типа переменной highPriority. Теперь переменная highPriority не получает значение пятого бита std::vector<bool>, возвращенного вызовом features.

Полученное ею значение зависит от того, как реализован тип std::vector<bool>::reference. Одна из реализаций таких объектов состоит в том, чтобы содержать указатель на машинное слово с интересующим нас битом и смещение этого бита в слове. Рассмотрим, что это означает для инициализации highPriority, в предположении, что имеет место именно такая реализация std::vector<bool>::reference.

Вызов features возвращает временный объект std::vector<bool>. Этот объект не имеет имени, но для упрощения нашего рассмотрения я буду называть его temp. Для temp вызывается operator[], в результате чего возвращается объект std::vector<bool>::reference, содержащий указатель на слово в структуре данных, хранящей интересующий нас бит (эта структура находится под управлением temp), плюс смещение в слове, соответствующее пятому биту. Переменная highPriority представляет собой копию этого объекта std::vector<bool>::reference, так что highPriority тоже содержит указатель на слово в temp плюс смещение, соответствующее пятому биту. В конце инструкции объект temp уничтожается, так как это объект временный. В результате переменная highPriority содержит висячий указатель, что и дает неопределенное поведение при вызове processWidget: