17

第一次提问者:) 是否可以在不破坏代码的情况下将全局 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)->doSomething(); . 因为pointer +=100不会指向第二个元素,而是第一个元素,甚至第零个元素,我不确定(不要忘记它是自动反编译的代码,因此很丑)。

我正在考虑将每个全局数组更改为 std::array 以及在没有[]运算符 to的情况下访问数组的每个实例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 是唯一特定于实现的东西,因为只有那些有实现定义的词(我手头没有最新的规范,因此可能存在一些其他差异)。

4

3 回答 3

4

对于一维数组,这可能适用于所有情况,二维情况更棘手:

原则上,std::array < > 模板可能只包含数组本身,因为它的长度参数是编译时变量,不需要存储。但是,您的 STL 实现可能已经选择存储它,或者它需要的任何其他数据。因此,虽然 '&a[n] == &a[0] + n' 适用于任何 std::array,但表达式 '&a[n][0] == &a[0][0] + n*arrayWidth' 可能不适用于 'std::array < std::array, arrayHeight >'。

您仍然可能想用您的 STL 实现检查 'sizeof(std::array < int, 100 >) == sizeof(int) * 100' 是否。如果是这样,即使替换 2D 数组也应该是安全的。

于 2013-06-15T08:07:50.333 回答
2

我想知道这种替换甚至应该如何在充满指针算术的代码中工作。

/// @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; 
              ^
于 2013-06-06T15:13:00.860 回答
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]:

数组的元素是连续存储的,这意味着 ifa是 an array<T, N>then 它服从&a[n] == &a[0] + nall的标识0 <= n < N

和 [class.mem 9.2 p20]:

指向标准布局结构对象的指针,使用 a 进行适当转换reinterpret_cast,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。[注意:因此,标准布局结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。——尾注]

无论如何,这取决于编译器和 STL 实现。但是反转的代码也取决于编译器。如果声明不是 a or的一部分,您为什么假设 inta; int b[50];将按该顺序定位a然后在内存中的数组,而不是在另一个中?出于性能原因,编译器会决定其他事情(但我认为这是不可能的)。bstructclass

于 2013-06-06T15:24:47.160 回答