Как объяснить неопределенное поведение новичкам всезнайки?

There'a горстка ситуаций, что стандарт C++ приписывает как неопределенное поведение. Например, если я выделяю с new[], затем попытайтесь освободить с delete (нет delete[]) это - неопределенное поведение - что-либо может произойти - оно могло бы работать, оно могло бы отказать злобно, оно могло бы повредить что-то тихо и посадить синхронизированную проблему.

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

35
задан Community 23 May 2017 в 12:31
поделиться

16 ответов

«Поздравляю, вы определили поведение компилятора для этой операции. Я ожидаю, что отчет о поведении других 200 компиляторов, существующих в мире, покажет будь у меня на столе к 10:00 завтра. Не разочаровывай меня сейчас, твое будущее выглядит многообещающим! "

21
ответ дан 27 November 2019 в 06:23
поделиться

Расскажите им о стандартах и ​​о том, как разрабатываются инструменты для соответствия стандартам. Все, что выходит за рамки стандарта, может работать или не работать, например UB.

0
ответ дан 27 November 2019 в 06:23
поделиться

Включить malloc_debug и удалить массив объектов с деструкторами. freeing указатель внутри блока должен выйти из строя. Вызовите их все вместе и продемонстрируйте это.

Нужно придумать другие примеры, чтобы построить свою достоверность до тех пор, пока они не поймут, что они новички, и что о С++ нужно знать очень много.

0
ответ дан 27 November 2019 в 06:23
поделиться

Один был бы...

"Это" использование не является частью языка. Если бы мы сказали, что в этом случае компилятор должен сгенерировать код, который ломается, то это была бы особенность, какое-то требование к производителю компилятора. Авторы стандарта не хотели давать ненужную работу над "особенностями", которые не поддерживаются. Они решили не предъявлять никаких поведенческих требований в таких случаях.

1
ответ дан 27 November 2019 в 06:23
поделиться

Скомпилируйте и запустите эту программу:

#include <iostream>

class A {
    public:
            A() { std::cout << "hi" << std::endl; }
            ~A() { std::cout << "bye" << std::endl; }
};

int main() {
    A* a1 = new A[10];
    delete a1;

    A* a2 = new A[10];
    delete[] a2;
}

По крайней мере, при использовании GCC он показывает, что деструктор вызывается только для одного из элементов при однократном удалении.

О однократном удалении на POD Укажите им FAQ по C ++ или попросите их запустить свой код через cppcheck .

1
ответ дан 27 November 2019 в 06:23
поделиться

C ++ на самом деле не является языком для дилетантов, и простое перечисление некоторых правил и их беспрекословное подчинение приведет к ужасным программистам; Большинство самых глупых вещей, которые, как я вижу, люди говорят, вероятно, связаны с таким слепым следствием правил / юристом.

С другой стороны, если они знают, что деструкторы не будут вызваны и, возможно, возникнут другие проблемы, они постараются этого избежать. И, что более важно, есть шанс отладить его, если они когда-нибудь это сделают случайно, а также иметь шанс осознать, насколько опасными могут быть многие функции C ++.

Поскольку есть много поводов для беспокойства, ни один курс или книга никогда не заставят кого-то освоить C ++ или, возможно, даже так хорошо освоить его.

2
ответ дан 27 November 2019 в 06:23
поделиться

Тихо переопределите new, new[], delete и delete[] и посмотрите, сколько времени ему потребуется, чтобы заметить ;)

Если это ... просто скажите ему, что он не прав и укажите ему на C++ spec. О да ... и в следующий раз будьте более осторожны при найме людей, чтобы избежать "дырок"!

3
ответ дан 27 November 2019 в 06:23
поделиться

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

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

EDIT: Замените rand () на mt _ rand () . Как отметил Майкл, это лучше, чем ранд .

-121--2424479-

Перед добавлением можно проверить list.contains () .

if(!list.contains(value)) {
    list.add(value);
}

Я предположил, что это будет очевидно! Однако добавление предметов в HashSet и последующее создание списка из этого набора было бы более эффективным.

-121--1266684-

Позвольте им попробовать себя, пока их код не потерпит крах во время теста. Тогда слова не понадобятся.

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

3
ответ дан 27 November 2019 в 06:23
поделиться

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

12
ответ дан 27 November 2019 в 06:23
поделиться

Мне приходят на ум две возможности:

  1. Вы могли бы спросить их: «Если бы вы могли проехать по шоссе в противоположном направлении в полночь и выжить, вы бы сделали это регулярно?»

  2. Более сложное решение могло бы быть чтобы настроить другую среду компилятора / запуска, чтобы показать им, как она терпит неудачу при различных обстоятельствах.

32
ответ дан 27 November 2019 в 06:23
поделиться

вместо этого можно использовать http://msdn.microsoft.com/en-us/library/system.windows.forms.screen.primaryscreen.aspx

-121--1517186-

, используя функцию boost:: assign.

vector<int> values;  
values += 1,2,3,4,5,6,7,8,9;

Подробно здесь

-121--1786978-

Просто цитируем из стандарта. Если они не могут принять это, они не программисты C++. Отрицали бы христиане Библию?; -)

1,9 Исполнение программы

  1. Семантические описания в этом Международном стандарте определяют параметризованную недетерминированную абстрактную машину. [...]

  2. Некоторые аспекты и операции абстрактной машины описаны в этом Международном стандарте как , определенные при внедрении (например, sizeof (int) ). Они составляют параметры абстрактной машины. Каждая реализация должна включать документацию, описывающую ее характеристики и поведение в этих отношениях . [...]

  3. Некоторые другие аспекты и операции абстрактной машины описаны в настоящем Международном стандарте как неуказанные (например, порядок оценки аргументов функции). По возможности этот Международный стандарт определяет набор допустимых вариантов поведения . Они определяют недетерминированные аспекты абстрактной машины. [...]

  4. Некоторые другие операции описаны в этом Международном стандарте как undefined (например, эффект дереференции нулевого указателя). [Примечание: настоящий Международный стандарт не предъявляет никаких требований к поведению программ, которые содержат неопределенное поведение . - end note]

Вы не можете получить больше ясности.

14
ответ дан 27 November 2019 в 06:23
поделиться

Просто покажите их Valgrind.

1
ответ дан 27 November 2019 в 06:23
поделиться

Мне нравится эта цитата:

Неопределенное поведение: оно может повредить ваши файлы, отформатировать диск или отправить письмо ненависти вашему боссу .

Я не знаю, кому это приписать (может быть, это из Effective C ++ )?

3
ответ дан 27 November 2019 в 06:23
поделиться

John Woods:

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

"Демоны могут вылететь из вашего носа" просто должно быть частью словарного запаса каждого программиста.

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

3
ответ дан 27 November 2019 в 06:23
поделиться

Неопределенный означает явно ненадежный. Программное обеспечение должно быть надежным. Больше ничего говорить не нужно.

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

48
ответ дан 27 November 2019 в 06:23
поделиться

То, что их программа кажется работающей, ничего не дает; компилятор может генерировать код, который работает (как вы вообще определяете «работу», когда правильное поведение undefined ?) в будние дни, но форматирует ваш диск по выходным. Читали ли они исходный код в свой компилятор? Изучить их дизассемблированный вывод?

Или напомнить им, что тот факт, что он «работает» сегодня, не гарантирует его работы при обновлении версии компилятора. Скажите им, чтобы они повеселились, находя в этом незаметные ошибки.

И действительно, почему , а не ? Они должны предоставить обоснованный аргумент в пользу использования неопределенного поведения, а не наоборот. Какая причина использовать delete вместо delete [] , кроме лени? (Хорошо, есть std :: auto_ptr . ​​Но если вы используете std :: auto_ptr с массивом, выделенным new [] , вам, вероятно, следует в любом случае использовать std :: vector .)

0
ответ дан 27 November 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: