Является ли переход массива C-Style в std:: array полностью безопасным для массивов?
первый раз вопрос :) Можно ли преобразовать глобальные массивы c-стиля в массивы std::без нарушения кода? Я работаю над проектом, который состоит из декомпиляции исходного кода старой игры. Нам уже удалось реструктурировать большую часть разборки/выход декомпиляции. Поскольку это автоматически, есть еще такие разделы, как
int a;
int b[50];
*(&a + 100) = xxx;
или
int b[50];
int a;
*(&a - 100) = xxx;
и другие типы сумасшедшей арифметики указателя, которые еще должны быть рефакторинг вручную. Но мы хотели бы использовать проверку границ для разделов, которые были (предположительно) правильно изменены на массивы.
(игнорировать текст курсивом, я держу его только для согласованности в комментариях)я нашел одну проблему до сих пор с chaning каждого массива:sizeof(class containing array)
изменится. Это может нарушить код в некоторых циклах, например
someclass somearray[100];
//например(sizeof (somearray[0]) == 50) имеет значение true
инт указатель = (int)somearray;
указатель += 100
((someclass)указатель) - >doSomething();
., потому что pointer +=100
не будет указывать на второй элемент, но где-то внутри первого или даже нулевого, я не уверен (не забывайте, что это автоматически декомпилированный код, отсюда уродство).
Я думаю изменить каждый глобальный массив на std:: array и каждый экземпляр доступа к массиву без []
оператор array._Elems
.
есть ли какие-либо проблемы это может возникнуть, если я должен изменить глобальные массивы на std:: arrays в коде, таком как этот?
редактировать Ты был прав насчет того, что размер не меняется. У меня была ошибка в функции проверки. Поэтому я расширю вопрос:
безопасно ли менять каждый массив c-style на std:: array?
редактировать Наш текущий код фактически выполняется только в режиме отладки, так как он не перемещает переменные. Выпуск падает режим в основном на старте программы.
редактировать Поскольку существует некоторая путаница в том, о чем этот вопрос, Позвольте мне уточнить: есть ли какая-то гарантия, что в массиве нет другого члена, кроме t elems [N] ? Могу ли я рассчитывать на
array<array<int,10>, 10> varname;
int* ptr = &varname[0][0];
ptr += 10
и убедитесь, что ptr указывает на varname[1][0]
независимо от деталей реализации? Хотя гарантируется, что массив является непрерывным, я не уверен в этом. Стандарт содержит реализацию, но я не уверен, что это пример реализации или фактическое определение, которого должна придерживаться каждая реализация с iterator и const_iterator, которые являются единственными вещами, специфичными для реализации, так как только у них есть слова реализация-определено (у меня нет последней спецификации под рукой, поэтому могут быть некоторые другие различия).
3 ответов
для одномерных массивов, это может работать во всех случаях, 2D случае сложнее:
в принципе, шаблон std::array может состоять только из самого массива, поскольку его аргумент length является переменной времени компиляции, которую не нужно хранить. Однако ваша STL-реализация, возможно, решила сохранить ее в любом случае или любые другие данные, которые ей нужны. Итак, в то время как '&a[n] == &a[0] + n 'выполняется для любого массива std::, выражение' &a[n][0] == &a[0][0] + Н*arrayWidth' не на 'с std::массив '.
тем не менее вы можете проверить, является ли 'sizeof(std::array ) == sizeof(int) * 100' с вашей STL-реализацией. Если это так, то должно быть безопасно заменить даже 2D-массивы.
интересно, как эта замена должна работать даже в коде, полном арифметики указателя.
/// @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;
^
это зависит от реализации STL. Я имею в виду, стандарт не мешает реализовать std::array
использование большего количества членов или резервирование большего объема памяти действительно необходимо (например, для отладки), но я думаю, что очень маловероятно найти один std::array
реализация не просто использовать T elem[N];
элемент данных.
если мы предположим, что реализация std:: array включает только одно поле для хранения данных и выделяет только необходимую память (не более), int v[100];
и где данные хранятся в array<int, 100> v;
будет иметь тот же макет, так как от стандартного:
[массив.обзор 23.3.2.1 p1]:
элементы массива хранятся смежно, что означает, что если
a
is Анarray<T, N>
тогда он подчиняется идентичности&a[n] == &a[0] + n
для всех0 <= n < N
.
и [класс.mem 9.2 p20]:
указатель на объект структуры стандартного макета, соответствующим образом преобразованный с помощью а
reinterpret_cast
, указывает на его первоначальный член (или если этот член бит-поле, затем к единице, в которой оно находится) и наоборот. [ Примечание: поэтому там может быть безымянный обивка внутри объект структуры стандартной компоновки, но не в его начале, как это необходимо для достижения соответствующего согласования. - конец Примечания ]
в любом случае, это зависит от компилятора и реализации STL. Но обратный код тоже зависит от компилятора. Почему вы предполагаете int a; int b[50];
найти a
и затем массив b
в памяти в этом порядке, а не в другом, если эти объявления не являются частью struct
или class
? Компилятор решил бы другое по соображениям производительности (но я вижу, что это маловероятно).