Как стать автором
Обновить

Комментарии 52

Си++, созданный в режиме совместимости с С, состоит из необъятного набора идиотских дефолтов и предположений. Компилятор — это как миноискатель. Не надо игнорировать его предупреждения, когда идёшь по минному полю.


Но у меня есть стратегия получше! Не ходите по минному полю даже с миноискателем. Используйте Rust, в котором безопасность кода является обязательной.

Минное поле, небезопасно, переходите на язык Абырвалг.
Типично.
Неинтересно.

Опять эти сказки. Если бы в нем «безопасность кода была обязательной», то в нем не было бы директивы unsafe (ну это не говоря уж о том, что и в нем UB вполне себе достижим даже в safe коде). Но без применения unsafe (как минимум на уровне отдельных модулей, а также стандартной библиотеки) ничего путного там не написать. Утверждения про «обязательную безопасность» кода в расте всегда напоминают мне берлинских экоактивистов, закрывавших паллетами от любопытных глаз дизельный генератор в своем лагере.

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


Разница между "развести костёр в середине комнаты" и "случайно наступить на мину" определяет разницу между мирным и (после)военным временем.


Лямбды с замыканием, которое вызывает use after free — это один из примеров, когда С++ пытается на С натянуть шкуру приличного языка, но получается даже хуже, чем было до.

Я бы, скорее, сравнил C++ с газопроводом или газовым котлом. Полезная вещь в быту? Безусловно. Что будет, если неподготовленный человек туда полезет? Скорее всего — взрыв, или, как нынче принято выражаться, «хлопок газа». А раст я бы сравнил с электричеством — несколько более безопасно на бытовом уровне (хотя регулярно и случаются пожары из-за коротких замыканий), но в высоковольтный трансформатор без допуска все равно лучше не лезть.

Эта аналогия обладает одним свойством — "безопасность" при этом выглядит производной от физических (неизменных) свойств. Газы горючи и ничего с этим не сделать.


А в реальности же — Си++ писали люди. Ладно, Си, его писали во времена, когда struct был слаще мёда для людей из ассемблера. Но Си++ писался уже по мотивам боли индустрии, и в этот момент было принято множество нетривиальных решений о дефолтах компилятора, дающих unsound код (выглядит прилично, а soundness нет).


Если бы в С++ были другие дефолты поведения — язык бы от этого медленнее не стал, а безопаснее — стал бы.

Ну что поделать, таковы были трейдоффы за возможность без модификации и написания разнообразных оберток использовать уже существовавшую огромную массу кода, написанного на C. Я бы сказал, что это решение себя оправдало. Оправдает ли в случае раста решение разработать очередной язык «с нуля» — будем поглядеть, пока это не очевидно. Вполне возможно, что он так и останется нишевым, как Ada, Oberon или D.
таковы были трейдоффы за возможность без модификации и написания разнообразных оберток использовать уже существовавшую огромную массу кода, написанного на C.

О, я обожаю этот вопрос. Действительно вызов Си кода из С++ кода не выглядит очень сложным или страшным, но там все равно целая бездна всяких нюансов ) Обратное — это вообще сплошная боль, чего только стоит extern C и всякий манглинг

Ну, это все равно попроще, чем, скажем, тот же JNI на мой взгляд.

и в нем UB вполне себе достижим даже в safe коде

А можно про это поподробнее?

Почитайте про флаг -Zsaturating-float-casts и про историю его появления.

Так они же это исправили?

Ну, sort of — через добавление костыля в виде опционального флага. А опциональный он потому, что в случае его использования производительность в ряде сценариев работы с числами с плавающей точкой заруливается в минуса. Думайте сами, считать это «исправлением» или нет.
Ну, sort of — через добавление костыля в виде опционального флага

Э… ну насколько я знаком с разработкой rustc это не так. Флаги начинающиеся -Z это так называемые фича флаги, они работают только в альфа/ночном релизе и служат для тестирования новых идей. В данном случае насколько исправление замедляет код тестеров. При запуске со стабильной версией компилятор просто скажет или выругается или просто проигнорирует '-Z" опции.


в ряде сценариев работы с числами с плавающей точкой заруливается в минуса

Увидел только один вариант который замедлился i128 -> f32, но и его исправили:
https://github.com/rust-lang/rust/pull/67328

Насколько я вижу, проблема существует до сих пор, даже на nightly:

play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=5c295dd26d187d13c059125bb604c40a

В целочисленных переменных после конверсии по-прежнему произвольный мусор, к тому же разный в debug и release.

P.S. Ссылка про i128 -> f32 не имеет к этой проблеме никакого отношения. Вот ссылка на соответствующий issue:

github.com/rust-lang/rust/issues/10184

Как видите, она до сих пор open (уже больше 6 лет), и в ней написано про negative performance impact от saturating float casts. Судя по всему, решения без performance impact до сих пор нет.

Ну, значит, надо брать не раст, а ещё более безопасные языки.

Ну если «безопасность языка» является единственным значимым фактором, то безусловно :) Пусть берут.

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

-Wall -Wextra конечно обязательны. Полезно было прочесть про другие флаги и рекомендации.

Уточнение:
-Woverloaded-virtual
Предупреждает о попытке в классе-наследнике переопределить виртуальную функцию базового класса
Переопределение виртуальной функции базового класса в классе-наследнике как раз нормально — она для этого, собственно, и предназначена, а вот перегрузка — это да, скорее всего ошибка.

Спасибо, поправлю. Речь, конечно же, о ситуации, когда новое определение функции в наследнике скрывает виртуальную функцию базового класса.

НЛО прилетело и опубликовало эту надпись здесь
И на такое
int a = 0;
if (cond)
   a = 2;
else
   a = 1;
получаем предупреждение: что-то на тему «присваивание значения, которое не используется».
НЛО прилетело и опубликовало эту надпись здесь

В реальном коде бывает и не такое.

НЛО прилетело и опубликовало эту надпись здесь

Лучше по какому критерию?

НЛО прилетело и опубликовало эту надпись здесь

Я против инициализации по-умолчанию в очевидных местах (когда значение переменной задается чуть ниже объявления).


if(нажата кнопка) a=1;
else a=2;

Каким значением инициализировать переменную a, нулем? Я вот когда вижу проинициализированную переменную сразу начинаю беспокоится: что её текущее значение означает для системы? Возвращаясь к примеру, может же так быть, что 0 — кодирует факт двойного нажатия на кнопку? А в случае двойного нажатия система выключается… Это ведь совсем не то, что я хотел.
А когда переменная не инициализирована — я спокоен, что инициализирую её ниже корректным значением в зависимости от условий.

int keyKode=KEY_NONE;
if(нажата кнопка) keyKode=KEY_ONE;
Хороший язык C++. Так много хороших способов, после того как отстрелишь себе ногу, исправить ситуацию, пришить ногу обратно, пересадить другую ногу, сделать протез, протез всегда можно взять чуть подлиньше, чуть по короче.
Java

И как, нраица?

Да.

Я пишу на плюсах и на хаскеле (стараюсь на первом поменьше, на втором — побольше) и согласен с предыдущим оратором.

Бывает.

Ещё есть любопытный ключик -Weffc++, который ссылается на книжку "Эффективный и современный С++". Его правила тоже было бы не плохо хотя бы перечислить.

Офигенный ключ, но, к сожалению, в нём есть неотключаемое правило, которое вообще не даёт создать невиртуальный деструктор. А это слишком сильное требование.
Но ради интереса можно временно включать, да.

Разве нельзя данное конкретное предупреждение подавить через pragma disable?

Я такого способа не знаю. Если знаете, покажите, пожалуйста, буду благодарен.

Можно заигнорить как "-W...", так и определённые файлы/строки. А вот валится ли правило про невиртуальный деструктор в общую кучу -Weffc++ или у него есть собственный ключ, чтобы не мучаться с исключением по строкам — не знаю. Вообще этот ключ не советуют использовать из-за размытости, а с -Werror с ним можно застрелиться.

Это всё понятно. Мы же говорим о том, как исключить из -Weffc++ одну конкретную диагностику. Отдельного ключа у неё, естественно, нет.

Тогда в тексте программы, где ругается на виртуальный деструктор


  //Вот тут -Weffc++ ещё работает   
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
  //Вот тут -Weffc++ не сработает                      
#pragma GCC diagnostic pop
  //Вот тут -Weffc++ уже работает   

Так можно, да. Но многовато будет прагм.

Можно через cmake иметь разный набор компиляции для разных файлов, но это, имхо, ещё более геморройно, чем прагмы прописывать.

И удивительно, что очень малая их часть включена по умолчанию

А ничего удивительного — сначала находятся уникумы, компилирующие с «treat warnings as errors», потом выходит новая версия с новыми предупреждениями, потом багтрекер компилятора заваливают репортами «ааааа вы сломали нам билд», потом разработчики компилятора решают, что ну его нафиг и делают новые предупреждения выключенными по умолчанию.
Коротче, те же яйца что и с ABI, только в профиль.

Я считаю, что и комитет, и компиляторщики уделяют слишком много внимания проблемам говнокодеров.

Это вы ещё не спрашивали мейнтейнеров пакетов в дистрибутивах, как они к -Werror относятся. Хинт: очень плохо, и почти всегда выпиливают этот флаг.

Прошу помощи у сообщества!
Можно ли защититься от случая, когда в одном файле
char arr[1];
а в другом extern char arr[999];
? Компилятор же должен видеть, что arr это и есть arr, почему его не смущает разный их размер?

А С++17 можно делать inline вместо extern, и объявлять таким образом один раз только в хедере. Так же в С++ имеет смысл использовать std::array.

А вообще компилятор ругается когда extern определение не совпадает с обычным. Видимо вы не везде хедер заинклюдили.

technic93 прошу прошения, сразу не отметил. Язык — только Си.
Может быть izvolov или 0xd34df00d знает?

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.