В С++ доступ к неинициализированному массиву неуказанного поведения или неопределенного поведения?

Например, в следующем коде:

int myarray[3];
int x = myarray[1];

Гарантируется ли успешное выполнение кода за постоянное время, когда x имеет некоторое целочисленное значение? Или компилятор может полностью пропустить вывод кода для этого или выдать код для запуска GNU Chess и при этом соответствовать стандарту C++?

Это полезно в структуре данных, похожей на массив, но может быть инициализирована за постоянное время. (Извините, у меня нет под рукой моей копии Ахо, Хопкрофта и Ульмана, поэтому я не могу найти имя.)


person Martin C. Martin    schedule 06.04.2018    source источник
comment
Это неопределенное поведение. :)   -  person Vlad from Moscow    schedule 06.04.2018
comment
@VladfromMoscow у вас есть ссылка на спецификацию?   -  person Martin C. Martin    schedule 06.04.2018
comment
В вашем примере поведение undefined, но вы можете безопасно взять ссылку или указатель на элемент и присвоить значение: auto& x = myarray[1]; x = 123;. Это то, что вам нужно для вашего алгоритма?   -  person Christian Hackl    schedule 06.04.2018
comment
Это попахивает вопросом X/Y. Что означает возможность инициализации за постоянное время? Где вы его инициализируете? В любом случае: возможный дубликат C/C++ результата неинициализированного массива   -  person underscore_d    schedule 06.04.2018
comment
@underscore_d Думайте об этом как о классе ConstantTimeArray с тремя методами: T get(i), void set(i, T) и eraseAllTo(T). Все три метода занимают время O(1) независимо от размера массива. См. cs.stackexchange.com/questions/492/ для реализации. Реализация также есть в книге «Алгоритмы + структуры данных» Ахо, Хопкрофта и Ульмана.   -  person Martin C. Martin    schedule 06.04.2018
comment
@ChristianHackl Спасибо, но этого недостаточно. Мне нужно иметь возможность получить значение из массива. Затем, основываясь на некоторых сравнениях и используя его для индексации в другой массив, я могу определить, действительно ли значение уже установлено, или оно является ненужным и его следует игнорировать.   -  person Martin C. Martin    schedule 06.04.2018
comment
Вы не можете этого сделать. В C/C++ нет нежелательного состояния. Это не SQL! Объект либо имеет значение, которое вы можете прочитать с любой степенью предсказуемости и определенности, либо нет.   -  person underscore_d    schedule 06.04.2018
comment
@MartinC.Martin: Как бы вы отличили случайное ненужное значение от действительного значения?   -  person Christian Hackl    schedule 06.04.2018
comment
@MartinC.Martin: Кстати, учитывая то, как вы просили спецификацию, вот информация о том, как получить либо дорогой официальный документ ISO, либо бесплатный последний черновик: isocpp.org/std/the-standard   -  person Christian Hackl    schedule 06.04.2018
comment
@underscore_d: Ну, в SQL тоже нет нежелательного состояния. NULL - это определенная, действительная вещь. Современным эквивалентом C++ будет std::optional.   -  person Christian Hackl    schedule 06.04.2018
comment
вопрос в том, является ли это автоматическим хранилищем или хранилищем процессов/потоков? Инициализация по умолчанию для глобального массива будет инициализацией значения нулем.   -  person Swift - Friday Pie    schedule 06.04.2018
comment
@underscore_d возможно, если данные защищены какой-либо проверкой работоспособности. Но очевидно случайные данные могут случайно попасть в проверку работоспособности. Вопрос в том, является ли это приемлемым случаем   -  person Swift - Friday Pie    schedule 06.04.2018
comment
@underscore_d Вы говорите, что в C++ нет такого понятия, как неопределенное поведение? А как насчет int f(int &x) { x=2; return 3;} int g(int &x) { x = 55; return 9;} int a; f(a) + g(a);? Значение a равно 2 или 55, но стандарт не говорит, какое именно. То же самое для foo(b++, b++), не указано, какое приращение происходит первым, но это не неопределенное поведение.   -  person Martin C. Martin    schedule 06.04.2018
comment
@ChristianHackl прочитал первый ответ здесь, они сказали это лучше, чем я: cs.stackexchange.com/questions/492/   -  person Martin C. Martin    schedule 06.04.2018
comment
@MartinC.Martin: Если я правильно понимаю, псевдокод в этом ответе предполагает, что каждый элемент в V начинается с неуказанного, но допустимого значения, поэтому сравнение V[i] < pos дает определенные результаты. Стандартный C++ не гарантирует, что это предположение выполняется, потому что такая гарантия сделает язык неприменимым для компьютерных архитектур, где определенные битовые комбинации в памяти или регистрах ЦП не представляют действительные целые числа (или другие типы).   -  person Christian Hackl    schedule 06.04.2018
comment
@MartinC.Martin: Кстати, да, в C++ есть неопределенное поведение, но это не то же самое, что неопределенное поведение. См. §3.27 и §3.28 стандарта ISO.   -  person Christian Hackl    schedule 06.04.2018
comment
@ChristianHackl Правильно, NULL четко определено. Я имел в виду, что OP нужен надежный способ проверить, установлено ли что-то. Что невозможно, потому что для того, чтобы этот флаг был надежным, кто-то сначала должен его установить... тем самым разрушая любые попытки использовать его для повышения производительности.   -  person underscore_d    schedule 07.04.2018
comment
@MartinC.Martin Давай. Вам нужно надежное состояние, которое указывает «не установлено, но определенно не установлено». Я сказал, что этого не существует. Как это означает, что я отрицаю существование неопределенного поведения? Это разные вещи.   -  person underscore_d    schedule 07.04.2018
comment
@Swift ОП, по-видимому, хочет избежать инициализации памяти из соображений производительности. Как вообще может помочь требование ОС/среды выполнения/что бы то ни было инициализировать его до нуля или какого-либо другого защитного значения?   -  person underscore_d    schedule 07.04.2018


Ответы (2)


Это неопределенное поведение.

Согласно стандарту ([dcl.init] параграф 12),

Если для объекта не указан инициализатор, объект инициализируется по умолчанию. При получении хранилища для объекта с автоматическим или динамическим сроком хранения объект имеет неопределенное значение, и если для объекта не выполняется инициализация, этот объект сохраняет неопределенное значение до тех пор, пока это значение не будет заменено . .. Если в результате оценки получено неопределенное значение, поведение не определено, за исключением следующих случаев.

со всеми следующими случаями, касающимися доступа к беззнаковому узкому символьному типу или std::byte, что может привести к неопределенному значению вместо того, чтобы быть неопределенным.

person 1201ProgramAlarm    schedule 06.04.2018
comment
Спасибо за внимание к спецификации! Я не уверен, как я обойду это, но, может быть, есть способ... - person Martin C. Martin; 06.04.2018

Доступ к любым неинициализированным данным является поведением undefined.

person Mikaela Szekely    schedule 06.04.2018
comment
Не думаю, что это верно для всех типов. См. stackoverflow.com/a/11965368/2757035. Разница между undefined и unspecified важна. - person underscore_d; 06.04.2018
comment
@underscore_d, это вопрос C, это версия C++ - person Shafik Yaghmour; 06.04.2018
comment
@ShafikYaghmour Спасибо за нюанс. Итак, моя точка зрения остается неизменной: некоторые типы в худшем случае производят неопределенные значения, а не неопределенные. - person underscore_d; 06.04.2018
comment
@ShafikYaghmour: Чтение неинициализированного unsigned char по-прежнему не является UB в C++, не так ли? - person Christian Hackl; 06.04.2018
comment
он по-прежнему не определен, если не сделаны какие-то другие вещи... пункт в стандартном списке получил маркер, когда он дает неопределенный результат - person Swift - Friday Pie; 06.04.2018