Особенности «всей команды» C ++?

16

В C ++ такие функции, как исключения, влияют на всю вашу программу: вы можете либо отключить их во всей программе , либо вам нужно иметь дело с ними во всем коде. Как говорится в известной статье о C ++ Report :

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

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

Следовательно, исключения являются функцией «всей программы» или «всей команды», так как они должны быть понятны каждому в команде, использующей их. Но не все функции C ++ такие, насколько я знаю.

Возможный пример: если я не получаю шаблоны, но не использую их, я все равно смогу написать правильный C ++ - или нет? Я даже могу вызывать sortмассив целых чисел и наслаждаться его удивительным преимуществом в скорости. C qsort(потому что не вызывается указатель на функцию), без риска ошибок - или нет? Кажется, шаблоны не являются "целой командой".

Существуют ли другие функции C ++, которые влияют на код, не использующий их напрямую, и, следовательно, являются «целой командой»? Меня особенно интересуют функции, отсутствующие в C.

Обновление : я особенно ищу функции, где нет языковых знаков, о которых вам нужно знать. В первом ответе я упомянул о правильности const, которая также является целой командой, поэтому каждый должен узнать об этом; однако, AFAICS, это повлияет на вас только в том случае, если вы вызовете функцию, которая помечена const, и компилятор не позволит вам вызывать ее для неконстантных объектов, так что вы получите что-то, что нужно Google. За исключением, вы даже не получите это; кроме того, они всегда используются, как только вы используетеnew , поэтому исключения более «коварны». Поскольку я не могу сформулировать это так объективно, я буду признателен за любую особенность всей команды.

Обновление 2 : вместо функции C ++ я должен был написать что-то вроде «C ++ - специфической функции», чтобы исключить такие вещи, как многопоточность, которые применяются к большому количеству основных языков программирования.

Приложение: Почему этот вопрос объективен (если вам интересно)

C ++ является сложным языком, поэтому многие проекты или руководства по кодированию пытаются выбрать «простые» функции C ++, и многие люди пытаются включить или исключить некоторые из них в соответствии в основном с субъективными критериями. Вопросы об этом регулярно закрываются здесь, на SO.

Выше я вместо этого определил (настолько точно, насколько это возможно), что такое языковая функция «для всей команды», приведу пример (исключения) вместе с обширным подтверждающим свидетельством в литературе о C ++ и запросил возможности для всей команды в C ++. за исключениями.

Должны ли вы использовать функции «целой команды», или это релевантная концепция, может быть субъективным - но это только означает, что важность этого вопроса субъективна, как всегда.

Blaisorblade
источник

Ответы:

11

Я бы назначил параллелизм как функцию «всей команды».

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

Барт ван Инген Шенау
источник
Я согласен с тем, что потоки - это такие функции для всей команды, хотя они не специфичны для C ++. Однако есть и другие интерфейсы для параллелизма (не основанные на потоках), в основном на других языках, и некоторые из них позволяют гораздо лучше инкапсулировать параллелизм (хотя это все еще актуальная тема исследований в языках программирования). Так что остается открытым вопрос, относится ли это к параллелизму per se.
Blaisorblade
@Blaisorblade - C ++ 11 представил свою собственную библиотеку потоков, так что да, теперь она является частью C ++.
Майкл Кохн
@MichaelKohne: я не утверждал, что C ++ не поддерживает многопоточность. Я сказал, что потоки не являются специфичными для C ++, потому что они есть во многих других языках. Я только что отметил, что описанные проблемы относятся к потокам как к интерфейсу для параллелизма.
Blaisorblade
Я бы сказал, что «условие гонки» - лучшее слово для этой основной проблемы. То есть программистам, возможно, вообще не нужно работать над средой параллелизма или использовать ее, но если они пишут какой-либо код C ++, и их код может быть потенциально вызван из более чем одного потока, тогда им нужно думать об условиях гонки в целом, во всем их коде написано.
Руон
Это напоминает мне о недопонимании с коллегой, которое произошло много лет назад. Коллега спросил другого коллегу: эта (некоторая функция) поточно-ориентирована? Другой сотрудник ответил да. Затем сотрудник, который спросил, продолжил использовать его из нескольких потоков и получил неожиданные результаты (он не падал, но несколько операций были применены к одному и тому же объекту). Оказалось, что коллега, который спросил, не имел ментальной модели того, что означает «потокобезопасный», и ошибочно принял ответ «я могу делать все, что захочу».
Руон
10

Очевидный ответ - constправильность: поскольку const/ volatilequalification является заразным, после того, как одна часть кода начала его использовать, каждый (прямо или косвенно) вызывающий код также должен быть constправильным или constявно отбрасывать ness.

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

Конрад Рудольф
источник
2
Более того, const-корректность прозрачна: она касается только типа, который вы даете функции (которая всегда видна), и компилятор будет кричать на вас, если вы ошиблись. Я думал о более непрозрачных вещах, когда вы не представляете, что что-то не так, пока не стало слишком поздно (и даже тогда это будет трудно понять). Но ваш ответ в любом случае интересен, поэтому проголосовал.
Blaisorblade
10

Указатели.

  • Указатель указывает на память в стеке?
  • Указатель указывает на память в куче?
  • Указатель указывает на один объект?
  • Указатель указывает на массив?
  • Указатель указывает на местоположение в середине массива?
  • Указатель действителен?
  • Указатель поврежден?
  • Какой код "владеет" указателем?
  • Должен ли объект, на который ссылаются, быть освобожден вручную? Если так, то как?
Томас Эдинг
источник
1
+1 конкретно из-за вопроса о владении указателем. Без умных указателей право собственности действительно распространяется на всю команду.
JKor
3

Другая возможность - перегрузка оператора. Как только одна часть кодовой базы начинает возиться с перегруженными операторами, все начинают вторую догадываться, что именно делает на самом деле любой данный объект, с которым они работают . Он явно не распространяется через кодовую базу, как это делают исключения и правильность констант, но это определенно то, что может начать вызывать проблемы, если вся команда не будет на одной странице о том, когда, как и зачем ее использовать.

Evicatos
источник
1

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

std::ostream& operator<< (std::ostream&, MyClass const&) {...}
std::istream& operator>> (std::istream&, MyClass&) {...}

... Но как только вы это сделаете, у вас никогда не будет никаких гарантий, что то, что вы пытаетесь написать (или, самое главное, прочитать), следует тому же формату, что и то, что отправляет вам клиент. С потоками происходит слишком много странных случаев, еще хуже, если вам приходится передавать потоки или флаги потоков в качестве аргументов по цепочке вызовов функций… именно так обычно реализуется потоковая передача классов. Таким образом, потоковая передача может быть определена как «коварная», как вы использовали вышеупомянутый термин, или, возможно, даже как «вирусная» ( хотя и нигде в той же степени, что и const-правильность ).

У вас есть член глубоко в вашей иерархии классов string? Сюрприз, клиент лучше отправляет одно слово, или иначе. У вас есть номера, которые вы хотите сериализовать? Вам лучше проверять, сохранять и восстанавливать флаги потока на каждой глубине вызова функции, потому что вы никогда не знаете, кто идиот, который просто установил свой поток в восьмеричный вывод перед вызовом вашей функции. Или хуже - кто только что вызвал что-то вроде setfillи, setwтаким образом, нарушил форматирование ввода / вывода вашего первого и только ваших первых целочисленных членов, потому что эти состояния не распространяются . Да, и давайте не будем спрашивать о потоках и интернационализации.

На языке нет никаких предупреждений о том, что вы транслируете в правильном направлении, или в неправильном направлении, или даже в потоковом режиме вообще . Запрашиваемый клиентский код для потока, чтобы передать для записи резервной копии данных? У вас нет способа узнать, на что указывает поток /dev/null. ( С другой стороны, вы можете претендовать на невероятную скорость резервного копирования и степень сжатия таким образом! )

Луис Мачука
источник