Утверждается ли, что следующий код при каждой совместимой оптимизации компилятора возвращает значение 14
? Это рекомендуется использовать? Является ли это более эффективным, чем введение двух указателей в общий массив? Есть ли у приведенной ниже техники стека конкретное имя? Какая лучшая практика дает точно такой же двоичный файл при компиляции с разумными или замечательными предположениями?
#include <iostream>
class A{
public:
double x[10];
double y[10];
};
int main(){
A a;
a.y[3] = 14;
std::cout << a.x[13] << "\n";
}
Где я могу найти такие определения? (ссылки, ссылки). Я предполагаю, что есть трюк для эффективного чтения стандарта.
Нет такого требования. Если вы получаете результат, которого ожидаете, то только случайно.
Это неопределенное поведение для каждого совместимого компилятора. Кроме того, static int[10]
не должен компилироваться с GCC g++ 11.3.0.
Один вопрос на вопрос, пожалуйста. Хотя в данном случае ответ один - не работает.
Возможный дубликат stackoverflow.com/questions/1239938/…
Помните, что C++ не обязательно должен использовать стек и, следовательно, не заботится о порядке стека.
@user4581301 user4581301 в данном случае я думаю, что это просто фигура речи, вопрос больше о макете объекта, чем о стеке как таковом.
Язык C++ не гарантирует, что члены будут располагаться в памяти непрерывно. Компиляторам разрешено вставлять заполнение между элементами; но члены должны быть выложены в порядке объявления. Если вам нужны смежные значения, используйте массив.
@ThomasMatthews Я думаю, что проблема здесь глубже, чем заполнение и т. д. - компилятору разрешено полностью исключать незаконный код.
Некоторые люди уже указали в комментариях, что ваш код в настоящее время имеет неопределенное поведение.
Что касается упорядочения, вам гарантируется, что, как вы определили прямо сейчас, x
и y
находятся в порядке, то есть y
будет иметь более высокий адрес памяти, чем x
. Но между ними может быть отступ, чтобы было меньше перекрытий, чем вы ожидаете, или, возможно, вообще не было перекрытий. Кроме того, стандарт написан так, чтобы разрешать (но не требовать) проверку индексов массива на достоверность, поэтому даже если они находятся непосредственно рядом друг с другом, компилятору разрешено проверять это, поскольку вы определили x
как 10 элементов. , любая попытка индексации за пределами элемента 10 th потерпит неудачу (например, вызовет аппаратное прерывание или сбой).
Это оставляет вопрос о том, как получить желаемый результат, но с определенным поведением. У вас есть несколько вариантов. Один из них заключается в выделении одного массива и добавлении псевдонима, который позволяет обрабатывать его половину, как если бы это был отдельный массив:
#include<iostream>
class A{
public:
double x[20];
double *y = &x[10];
};
int main(){
A a;
a.y[3] = 14;
std::cout << a.x[13] << "\n";
}
Другое направление, в котором вы могли бы пойти, состояло бы в том, чтобы разделить два массива, но затем добавить небольшой прокси-сервер, чтобы разрешить адресацию в оба массива, как если бы они были одним:
#include<iostream>
class proxy {
double *x_;
size_t N;
double *y_;
public:
template <class T, std::size_t N>
proxy(T (&x_)[N], T *y) : x_(x_), N(N), y_(y) {}
double &operator[](std::size_t n) {
if (n < N)
return x_[n];
else
return y_[n-N];
}
};
class A{
double x_[10];
public:
double y[10];
proxy x{x_, y};
};
int main(){
A a;
a.y[3] = 14;
std::cout << a.x[13] << "\n";
}
Если вам действительно не нужно использовать отдельные массивы для двух элементов, первый, вероятно, предпочтительнее — он явно проще и, вероятно, быстрее.
Рассматривать два массива как один опасно, потому что слишком заманчиво использовать их так, как если бы они были смежными, например, пытаясь записать их в двоичный файл.
Это неопределенное поведение. Вы не можете гарантировать, что между массивами не будет заполнения.
Замечание: сегодня я узнал, что GCC g++ 11.3.0 на Ubuntu 20.04 с оптимизацией -O3 -march=native -ffast-math на sandybridge не будет инициализировать статический int[10] нулями. Вот почему я педантичен. Кроме того, мой код, возможно, придется запускать на встроенных целях, где компиляторы могут быть сомнительными; но давайте держать это как отдельное рассмотрение.