Выражения без побочных эффектов в C ++ - PullRequest
6 голосов
/ 10 ноября 2010

Понимаете, я не понимаю, почему такие программы должны быть легальными?

int main()
{ 
    static const int i = 0;
    i < i > i;
}

Я имею в виду, конечно, что никто на самом деле не имеет текущих программ, которые имеютвыражения без каких-либо побочных эффектов, поскольку это было бы очень бессмысленно, и это значительно упростило бы синтаксический анализ и компиляцию языка.Так почему бы просто не запретить их?Какую пользу на самом деле получает язык от использования такого синтаксиса?

Другой пример, подобный следующему:

int main() {
    static const int i = 0;
    int x = (i);
}

Какова реальная польза от таких утверждений?

И такие вещи, как самый неприятный анализ.Кто-нибудь когда-либо объявляет функции в середине других функций?Я имею в виду, мы избавились от таких вещей, как неявное объявление функций и тому подобное.Почему бы просто не избавиться от них для C ++ 0x?

Ответы [ 7 ]

8 голосов
/ 10 ноября 2010

Возможно, потому что запрет тогда усложнит спецификацию, что усложнит компиляторы.

4 голосов
/ 10 ноября 2010

это сделало бы разбор и компиляцию язык намного проще

Не понимаю как. Почему проще проанализировать и скомпилировать i < i > i, если вам требуется , чтобы выдать диагностику, чем анализировать ее, если вам разрешено делать все, что вам чертовски хорошо, при условии, что выданный код не имеет побочных эффектов?

Компилятор Java запрещает недоступный код (в отличие от кода без эффекта), что является смешанным благословением для программиста и требует немного дополнительной работы от компилятора, чем тот, который фактически требуется для компилятора C ++ ( базовый анализ зависимостей блоков). Должен ли C ++ запрещать недоступный код? Возможно нет. Несмотря на то, что компиляторы C ++, безусловно, проводят достаточную оптимизацию для выявления недоступных базовых блоков, в некоторых случаях они могут делать слишком много. Должен ли if (foo) { ...} быть недопустимым недостижимым блоком, если foo является ложной константой времени компиляции? Что, если это не постоянная времени компиляции, но оптимизатор выяснил, как рассчитать значение, если оно допустимо, и компилятор должен понять, что причина его удаления зависит от реализации, чтобы не выдавать ошибку ? Больше особых случаев.

никто на самом деле не имеет тока программы, которые имеют выражения без побочные эффекты в них

Нагрузки. Например, если NDEBUG имеет значение true, тогда assert расширяется до пустого выражения без эффекта. Так что в компиляторе требуется еще больше особых случаев, чтобы разрешить некоторые бесполезные выражения, но не другие.

Я полагаю, что логическое обоснование состоит в том, что если бы он расширился до нуля, то (а) компиляторы в конечном итоге выдавали бы предупреждения для таких вещей, как if (foo) assert(bar);, и (б) такой код был бы допустим при выпуске, но не при отладке что просто сбивает с толку:

assert(foo) // oops, forgot the semi-colon
foo.bar();

такие вещи, как самый неприятный анализ

Вот почему это называется "досадным". Это проблема обратной совместимости на самом деле. Если бы C ++ теперь изменил значение этих неприятных разборов, смысл существующего кода изменился бы. Как вы указали, не так много существующего кода, но комитет C ++ придерживается довольно сильной позиции в отношении обратной совместимости. Если вы хотите, чтобы язык менялся каждые пять минут, используйте Perl; -)

В любом случае, уже слишком поздно. Даже если бы у нас было отличное представление о том, что комитет C ++ 0x пропустил, почему какая-то функция должна быть удалена или несовместимо изменена, они не будут нарушать что-либо в FCD, если только FCD не имеет окончательной ошибки.

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

3 голосов
/ 10 ноября 2010
  • Иногда удобно помещать в программу бесполезные операторы и компилировать их просто для того, чтобы убедиться, что они законны - например, типы могут быть разрешены / сопоставлены и т. Д.

  • Особенно в сгенерированном коде (макросы, а также более сложные внешние механизмы, шаблоны, в которых политики или типы могут вводить бессмысленные расширения в некоторых неоперативных случаях), с менее специальными некомпилируемыми случаями, чтобы избежать их упрощения1008 *

  • Может быть некоторый временно прокомментированный код, который удаляет осмысленное использование переменной, но может быть затруднительно идентифицировать и комментировать все переменные, которые не используются в других местах.

  • В то время как в ваших примерах вы показываете, что переменные имеют значение «int» непосредственно над бессмысленным использованием, на практике типы могут быть намного более сложными (например, оператор <()) и то, имеют ли операции побочные эффектыможет даже быть неизвестным компилятору (например, функции вне строки), так что любые преимуществаЭто ограничено более простыми случаями. </p>

  • C ++ нуждается в веской причине, чтобы нарушить обратную (и сохраненную C) совместимость.

0 голосов
/ 10 ноября 2010

Выражения без побочных эффектов могут появляться чаще, чем вы думаете в шаблонах и макросах. Если вы когда-либо объявили std::vector<int>, вы создали экземпляр шаблона кода без побочных эффектов. std::vector должен уничтожить все свои элементы при освобождении, если вы сохранили класс для типа T. Для этого в какой-то момент требуется оператор, похожий на ptr->~T();, для вызова деструктора. int не имеет деструктора, поэтому вызов не имеет побочных эффектов и будет полностью удален оптимизатором. Также вероятно, что он будет внутри цикла, тогда весь цикл не будет иметь побочных эффектов, поэтому оптимизатор удаляет весь цикл.

Так что если вы запретите выражения без побочных эффектов, std::vector<int> не сработает , например.

Другой распространенный случай - assert(a == b). В выпусках сборки вы хотите, чтобы эти утверждения исчезли, но вы не можете переопределить их как пустой макрос, в противном случае такие операторы, как if (x) assert(a == b);, внезапно помещают следующий оператор в оператор if - катастрофа! В этом случае assert(x) можно переопределить как ((void)0), что является утверждением, которое не имеет побочных эффектов. Теперь оператор if работает корректно в сборках релиза - он просто ничего не делает.

Это всего лишь два распространенных случая. Есть еще много, о которых вы, вероятно, не знаете. Таким образом, хотя выражения без побочных эффектов кажутся избыточными, на самом деле они функционально важны. Оптимизатор удалит их полностью, поэтому также не будет влиять на производительность.

0 голосов
/ 10 ноября 2010

Возможно, оператор был перегружен, чтобы иметь побочные эффекты, такие как cout<<i; Это причина, почему они не могут быть удалены сейчас.С другой стороны, C # запрещает использовать в качестве операторов выражения не-присваивания или вызовов методов, и я считаю, что это хорошо, поскольку делает код более понятным и семантически правильным.Однако у C # была возможность запретить это с самого начала, чего нет у C ++.

0 голосов
/ 10 ноября 2010

Как итерация стандарта C ++, C ++ 0x должен быть обратно совместимым. Никто не может утверждать, что написанные вами заявления не существуют в каком-то критическом программном обеспечении, написанном / принадлежащем, скажем, NASA или DoD.

В любом случае, в отношении вашего самого первого примера, парсер не может утверждать, что i является статическим константным выражением, а i < i > i является бесполезным выражением - например, если i является шаблонным типом, i < i > i является «недопустимым объявлением переменной», а не «бесполезным вычислением» и все же не является ошибкой разбора.

0 голосов
/ 10 ноября 2010

Почему бездействие следует рассматривать как особый случай?Кроме того, хотя вышеперечисленные случаи легко обнаружить, можно представить гораздо более сложные программы, в которых не так легко определить, что побочных эффектов нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...