2015-10-08 5 views
5

В книге Скотта Мейера Эффективное Modern C++ мы можем прочитать, что:авто и static_casts - хорошая практика

std::vector<bool> features(const Widget& w); 
Widget w; 
… 
bool highPriority = features(w)[5]; 
… 
processWidget(w, highPriority); 

и вариант с автоматической

auto highPriority = features(w)[5]; 

, который вызывает неопределенное поведение, из-за факт, что features() возвращает std::vector<bool>, который использует прокси-объект типа std::vector<bool>::reference при возврате значения от opearator[].

В качестве решения этой проблемы рекомендуется не останавливать использование auto, но используя static_casts.

Так Скотт Мейерс совет использовать:

auto highPriority = static_cast<bool>(features(w)[5]); 

вместо:

bool highPriority = features(w)[5]; 

Мой вопрос: Что такое реальная разница между этими двумя? На мой взгляд, оба они одинаковы, потому что оба метода делают рефакторинг сложнее точно таким же образом (изменение типа возвращаемого значения в функциях функции не делает переменной highPriority другим типом), а вторая - более короткой для записи.

+1

Просто подозрение, но с моей головы я не могу думать о функциональном различии, и единственная причина Скотта может быть последовательностью - он не выступал за использование 'auto x =' для практического всего где-то в той же книге ...? (Или, может быть, это была какая-то статья в Интернете, которую я видел ...) –

+3

@TonyD Да, консистенция, вероятно, является причиной. Он предлагает «предпочитать« авто »для явных деклараций типов» в пункте 5 – TartanLlama

+1

Я бы сказал, что первое решение явно сообщает читателю: «дело не в bool, но я хочу, чтобы это было bool». Второе решение обычно говорит читателю: «Это bool или можно хотя бы использовать как таковое», но проблема в том, что большинство читателей читают его как «это bool» и, вероятно, «эй, теперь у нас есть« авто », поэтому мы пишем его 'auto highPriority = features (w) [5];'! "и стрела. Даже если оба решения технически идентичны, читатель сначала предупреждается, что может возникнуть проблема с непосредственным использованием 'features (w) [5]'. Кстати, та же проблема возникает с такими вещами, как шаблоны выражений. – leemes

ответ

7

Если вам не нравится интерфейс features, вы можете скрыть уродство в вспомогательной функции

bool is_high_priority(const Widget& w) 
{ return features(w)[5]; } 

и теперь ваши

auto highPriority = is_high_priority(w); 

работает, как ожидалось.

+0

Не могли бы вы рассказать мне, где именно? Приходящий из? Это какой-то новый оператор или что-то в этом роде? Является ли это особенностью компилятора? Я каким-то образом не могу найти его где-нибудь – DawidPi

+0

Это всего два отрицания подряд. '! x' превратит' x' в 'bool' (сравнивая его с 0), но с противоположным значением. '!! x' снова инвертирует значение'! x', создавая 'false' для нуля и' true' для ненулевого. –

5

С features функция, которая возвращает std::vector<bool>,

auto highPriority = features(w)[5]; 

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

Вместо делать

bool const highPriority = features(w)[5]; 

или

auto const highPriority = !!features(w)[5]; 

или, как Скотт рекомендует – но это слишком многословным, на мой вкус – использовать в static_cast.

Сохраненный объект теперь bool.

Не существует функциональной разницы между этими тремя способами выражения одной и той же декларации. Единственные отличия нефункциональны: по-моему, ненужная многословие static_cast и возможность того, что !! может подавить глупое предупреждение о производительности из одного общего компилятора.

0

Когда вы используете auto, auto выводит его как тип, возвращаемый highPriority, который является ссылкой на bool.Дело в том, что highPriority не возвращает ссылку на bool, а объект std :: vector :: reference. ('reference' - вложенный класс внутри std :: vector). std :: vector :: reference - это «прокси-класс», класс, который эмулирует поведение какого-либо другого типа. Это не только класс прокси, но и «невидимый» класс прокси. Такие классы не работают с авто. Auto не может правильно выводить тип невидимого прокси-класса. Но static_cast заставляет преобразование с высоким приоритетом в bool. Это позволяет избежать неопределенного поведения.

+0

вот что я сказал. Я попросил 2 возможных решения и почему Скотт Мейерс предпочитает первый – DawidPi

+0

Он не любит его. Есть разница. Его слова ... «cast изменяет тип выражения на bool, который автоматически выводит как тип highPriority. Во время выполнения объект std :: vector :: reference возвращается из std :: vector : : operator [] выполняет преобразование в bool, которое он поддерживает ... » Таким образом, статический приведение необходимо для изменения типа в bool FIRST для всех остальных. – dspfnder

+1

точно такое же исполнение выполняется, когда вы говорите 'bool highPrio ...' В первой и второй попытках нет разницы в исполнении. В обоих решениях производится литье, и это одно и то же. Один из них явный, подразумевается, что это единственное отличие. Результат тот же. – DawidPi

Смежные вопросы