Я хотел бы знать, не принят ли следующий код стандартом C++.Арифметика указателя: из привязки без разыменования
int n{ 10 };
double* p = new double[0];
double* q = p + n;
std::cout << "n = " << static_cast<int>(q - p) << std::endl;
Я хочу, чтобы эта программа отображала значение n.
Как этот вопрос может показаться странным, вот объяснение происхождения этой проблемы. Я хочу создать динамический класс массива в 2D (подумайте о std :: vector виде контейнера, но в 2D вместо 1D). Прямолинейный подход был бы:
template <typename T>
class Array2D<T> {
private:
T* data_;
int nb_rows_;
int nb_columns_;
public:
...
};
К сожалению, эта конструкция не SIMD дружеский как петля, такие как
Array2D<int> A(5, 6);
for (int i = 0; i < A.nb_rows(); ++i) {
for (int j = 0; j < A.nb_columns(); ++j) {
A(i, j) += 1;
}
}
провалится векторизации, как компилятор не может быть уверен, что если nb_columns_ не изменяется во время цикла из-за наложения указателя. Поэтому я использую тот же дизайн, что и большая реализация std :: vector, где размер вектора «скрыт» в указателе.
template <typename T>
class Array2D<T> {
private:
T* data_;
T* nb_rows_;
T* nb_columns_;
public:
Array2D(int n, int p) {
data_ = new T[n * p];
nb_rows_ = data_ + n;
nb_columns_ = data_ + p;
}
...
int nb_columns() const {
return static_cast<int>(nb_columns_ - data_);
}
...
};
Эта конструкция хорошо работает до тех пор, п> = 1 и р> = 1. Но при п = 0 и р = 5, вы в конечном итоге с такой «проблемы» пояснено выше. Построение Array2D с 0 строк может быть полезным из-за следующий метод в моем классе
void push_back(const Array1D<T>& B);
, которая принимает Array1D размера р (проверено с утверждаешь) и добавляет строку в моем объект Array2D. Вы можете сделать:
Array2D<double> A(0, 10);
Array1D<double> B(10);
// work with B
A.push_back(B);
код прекрасно работает на лязг, г ++ и ICPC, но я все еще интересно, если это действительно. Раздел 5.7 стандарта C++ 11 относится к этой проблеме, но говорит о «объектах массива». Мне интересно, указывает ли мой p на то, что они называют «объектом массива», или если объект массива является чем-то вроде «double p [5]».
@Joachim Pileborg: Я хотел бы быть в этом уверен. Можете ли вы привести этот стандарт в этом вопросе? Также может произойти переполнение указателя, поскольку data_ + n может переполняться. – InsideLoop
Я не знаю, что будет делать с нулевым размером массива? –
Как сказал Али Казми, что хорошо для массива нулевого размера? Не могли бы вы просто проверить, если n * p == 0, тогда просто возвращайтесь так: 'Array2D (int n, int p) { if (n * p == 0) return; data_ = new T [n * p]; nb_rows_ = data_ + n; nb_columns_ = data_ + p; } ' –