Подтвердить что ты не робот

Используемый случай указателя на массив с неопределенными границами в С++ (не в C)

Рассмотрим следующий код:

int main() {
    int (*p)[]; // pointer to array with unspecified bounds

    int a[] = {1};
    int b[] = {1,2};

    p = &a; // works in C but not in C++
    p = &b; // works in C but not in C++

    return 0;
}

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

struct C
{
    static int v[];
};

int main() 
{
    int (*p)[] = &C::v; // works in C++ if 'v' isn't defined (only declared)
    return 0;
}

Но не удалось найти полезный случай этого кода.

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

4b9b3361

Ответ 1

Такой указатель не может участвовать в арифметике указателя, потенциально полезные вещи, которые еще могут быть выполнены, - это получить его тип с decltype или reinterpret_cast его другим типом указателя или intptr_t. Это объясняется тем, что в разделе 3.9p6 говорится:

Тип класса (например, "class X" ) может быть неполным в одной точке единицы перевода и завершаться позже; тип "class X" является одним и тем же типом в обеих точках. Объявленный тип объекта массива может быть массивом неполного типа класса и, следовательно, неполным; если тип класса будет завершен позже в блоке перевода, тип массива будет завершен; тип массива в этих двух точках является одним и тем же типом. Объявленный тип объекта массива может быть массивом неизвестного размера и поэтому быть неполным в одной точке единицы перевода и заканчиваться позже; типы массивов в этих двух точках ( "массив неизвестной границы T" и "массив из N T" ) - это разные типы. Тип указателя на массив неизвестного размера или тип, определяемый объявлением typedef, как массив неизвестного размера, не может быть завершен.

5.3.1 говорит:

Примечание. Неверно указатель на указатель на неполный тип (кроме cv void). Полученное таким образом lval может использоваться ограниченным образом (например, для инициализации ссылки); это значение lvalue не должно быть преобразовано в prvalue, см. 4.1.

Так как распад матрицы к указателю может выполняться по массиву lvalues ​​без предварительного преобразования в rvalue, код dyp, оставленный в комментарии, правильный:

(*p)[i]

Соответствующее правило, от 4.2:

lvalue или rvalue массива типа N T "или " массив неизвестной границы T " можно преобразовать в значение prvalue типа" указатель на T". Результатом является указатель на первый элемент массива.

Ответ 2

Я думаю, что компилятор должен принять его (независимо от установки -O), потому что определение статики может быть предоставлено другим модулем компиляции. (Это, пожалуй, прагматичное отклонение от стандарта - я не эксперт на С++). Опубликованный фрагмент может быть скомпилирован, но он неполный и не может быть приведен в исполнение без определения статического члена.

Файл c.h:

struct C {
    static int v[];
};

Файл x.cpp

#include "c.h"
#include <iostream>
int main(){
    int (*p)[] = &C::v; // works in C++ if 'v' isn't defined (only declared)
    std::cout << *((int*)p) << std::endl; 
    return 0;
}

Файл y.cpp

#include "c.h"
int C::v[3] = {1,2,3};

Скомпилировано и связано с использованием (dont-tell-me-it -s-old) g++ 4.3.3. Печать 1.

И: да, я знаю, что это C.