Проблема здесь является правилом строгого сглаживания, которая существует в моих проектах n3337 для C++ 11 в 3.10 Lvalues и rvalues [basic.lval] § 10. Это исчерпывающий перечень, который не позволяет explicetely псевдонима многомерный массив до одномерного целого размера.
Таким образом, даже если это действительно необходимо, чтобы массивы выделяются последовательно в памяти, что доказывает, что размер многомерного массива, скажем, например T arr[n][m]
является продуктом является размер по размеру элемента: n * m *sizeof(T)
. При преобразовании в указатели на символы вы можете даже выполнять операции арифметического указателя по всему массиву, потому что любой указатель на объект может быть преобразован в указатель char, и этот указатель char может использоваться для доступа к последовательным байтам объекта (*), ,
Но, к сожалению, для любого другого типа, стандарт только позволяют операции арифметического указателя внутри одного массива (и по определению dereferening элемента массива тот же, как разыменования указателя после указателя арифметики: a[i]
является*(a + i)
). Так что, если вы оба соблюдать правила на стрелочных арифметике и строгое правило наложения спектров, глобальное индексирование многомерного массива не определяется C++ 11 стандарта, если не пройти через полукокса указатель арифметика:
int a[3][4];
int *p = &a[0][0]; // perfectly defined
int b = p[3]; // ok you are in same row which means in same array
b = p[5]; // OUPS: you dereference past the declared array that builds first row
char *cq = (((char *) p) + 5 * sizeof(int)); // ok: char pointer arithmetics inside an object
int *q = (int *) cq; // ok because what lies there is an int object
b = *q; // almost the same as p[5] but behaviour is defined
То, что char pointer arithmetics вместе со страхом сломать много существующего кода объясняет, почему весь известный компилятор молчаливо принимает наложение многомерного массива с 1D одного и того же глобального размера (он приводит к тому же внутреннему коду), но технически глобальная арифметика указателя действительна только для указателей на символы.
(*) Стандарт объявляет в 1.7 ++ модели памяти C [intro.memory], что
Устройство хранения фундаментального в модели памяти C++ является байтами ... Память доступна программа на C++ состоит из одной или нескольких последовательностей смежных байтов. Каждый байт имеет уникальный адрес.
и более поздние версии 3.9 Типы [основные.Типы] § 2
Для любого объекта (кроме базового класса подобъекта) из тривиального Copyable типа Т, выполняется ли или нет объекта действительного значение типа T, лежащие в основе байты, составляющие объект могут скопировать в массив символа char или unsigned.
и скопировать их, вы должны получить доступ к ним через char *
unsigned char *
или
Ну, я не мог найти что-либо непосредственно связаны с стандартом ISO C++. Но да, автоматически выделяемые массивы гарантированно сохраняются в памяти. И когда вы используете индексный оператор, т. Е. 'P [11]' на простой указатель, он эквивалентен '* (p + 11)', поэтому, если есть законные данные типа '* p', поведение определяется. – George
@George Layout гарантии и юридический доступ - это не одно и то же. Не путайте реализацию с требованиями абстракции. – Yakk
Я думаю, что '[expr.add]/5' может запретить это, но' [dcl.array]/1' гарантирует, что хранилище смежно. – NathanOliver