Является ли переход массива C-Style в std :: array полностью безопасным для массивов?

Впервые спрашивающий 🙂
Можно ли преобразовать глобальные массивы в стиле c в std :: arrays, не нарушая код? Я работаю над проектом, который состоит из декомпиляции исходного кода старой игры. Нам уже удалось реорганизовать большую часть результатов разборки / декомпиляции. Поскольку это автоматически, есть еще разделы, такие как

  int a;
int b[50];
*(&a + 100) = xxx;

или же

  int b[50];
int a;
*(&a - 100) = xxx;

и другие типы сумасшедшей арифметики указателей, которые еще предстоит изменить вручную. Но мы бы хотели использовать проверку границ для секций, которые (предположительно) были правильно изменены на массивы.

(Проигнорируйте текст курсивом, я держу это только для последовательности в комментариях)Я нашел одну проблему с изменением каждого массива: sizeof(class containing array) изменилось бы. Это может сломать код в некоторых циклах, например
Someclass Somearray [100];
// например (sizeof (somearray [0]) == 50) верно
int pointer = (int) somearray;
указатель + = 100
((SomeClass
) Указатель) -> йоЗотеЬЫпд ();
,так как pointer +=100 я бы не был уверен, что указывал бы на второй элемент, но где-то внутри первого или даже нулевого (не забывайте, что это автоматически декомпилированный код, отсюда и уродство).

Я думаю об изменении каждого глобального массива на std :: array и каждом экземпляре доступа к массиву без [] оператор для array._Elems,

Есть ли проблемы, которые могут возникнуть, если бы я изменил глобальные массивы на std :: arrays в коде, подобном этому?

редактировать
Вы были правы, что размер не меняется. У меня была ошибка в функциях тестирования. Поэтому я расширю вопрос:

Безопасно ли менять каждый массив в стиле c на std :: array?

редактировать
Наш текущий код на самом деле работает только в режиме отладки, поскольку он не перемещает переменные. Режим выпуска вылетает в основном при запуске программы.

редактировать
Поскольку, по-видимому, существует некоторая путаница в отношении этого вопроса, позвольте мне уточнить: есть ли какая-либо гарантия того, что в массиве нет другого члена, кроме T elems [N]?
Могу ли я рассчитывать на

array<array<int,10>, 10> varname;
int* ptr = &varname[0][0];
ptr += 10

и убедитесь, что ptr указывает на varname[1][0] независимо от деталей реализации? Хотя гарантируется, что массив является смежным, я не уверен в этом. Стандарт содержит реализацию, но я не уверен, является ли это примерной реализацией или фактическим определением, которое каждая реализация должна придерживаться, итераторы и const_iterator являются единственными вещами, которые специфичны для реализации, так как только те, у которых есть слова от реализации (У меня нет последней спецификации под рукой, поэтому могут быть некоторые другие различия).

15

Решение

Для одномерных массивов это может работать во всех случаях, 2D-случай более сложный:

В принципе это возможно для std :: array < > шаблон должен состоять только из самого массива, потому что его аргумент длины является переменной времени компиляции, которую не нужно хранить. Тем не менее, ваша STL-реализация могла бы в любом случае сохранить ее или любые другие необходимые данные. Так что пока ‘&a [n] == &a [0] + n ‘верно для любого std :: array, выражение’&a [n] [0] == &[0] [0] + n * arrayWidth ‘может не сохраняться для’ std :: array < std :: array, arrayHeight> ‘.

Тем не менее, вы можете проверить, есть ли sizeof (std :: array < int, 100>) == sizeof (int) * 100 ‘с вашей STL-реализацией. Если это произойдет, будет безопасно заменить даже двумерные массивы.

3

Другие решения

Интересно, как эта замена должна даже работать в коде, полном арифметики указателей.

/// @file array_eval.cpp
#include <iostream>
#include <array>
#include <algorithm>int main() {
auto dump = [](const int& n){std::cout << n << " ";};

#ifdef DO_FAIL
std::array<int, 10> arr;
#else
int arr[10];
#endif

// this does not work for std::arrays
int* p = arr;

std::for_each(p, p+10, dump);
std::cout << std::endl;
return 0;
}

А также

g++ -Wall -pedantic -std=c++11 -DDO_FAIL array_eval.cpp

конечно не получается

array_eval.cpp: In function ‘int main()’:
array_eval.cpp:17:14: error: cannot convert ‘std::array<int, 10ul>’ to ‘int*’ in initialization
int* p = arr;
^
2

Это зависит от реализации STL. Я имею ввиду, стандарт не мешает внедрять std::array использование большего количества членов или резервирование большего количества памяти на это действительно необходимо (например, для отладки), но я думаю, что очень маловероятно найти один std::array реализация без просто использовать больше T elem[N]; элемент данных.

Если мы предположим, что реализация std :: array включает в себя только одно поле для хранения данных и выделяет только необходимую память (не более), int v[100]; и где данные хранятся в array<int, 100> v; будет иметь такой же макет, так как из стандарта:

[array.overview 23.3.2.1 p1]:

Элементы массива хранятся непрерывно, что означает, что если a является
array<T, N> тогда он подчиняется личности &a[n] == &a[0] + n для всех 0 <= n < N,

и [class.mem 9,2 p20]:

Указатель на объект структуры стандартной компоновки, соответствующим образом преобразованный с использованием
reinterpret_cast, указывает на своего начального члена (или если этот член
битовое поле, затем к единице, в которой оно находится) и наоборот. [
Примечание. Следовательно, в пределах
стандартный объект структуры структуры, но не в начале, по необходимости
добиться соответствующего выравнивания. —Конечная записка]

В любом случае, это зависит от компилятора и реализации STL. Но обратный код тоже зависит от компилятора. Почему вы принимаете Int a; int b[50]; найдет a а затем массив b в памяти в этом порядке, а не в другом, если эти объявления не являются частью struct или же class? Компилятор решит другое по соображениям производительности (но я вижу, что это маловероятно).

2
По вопросам рекламы [email protected]