为何无关代码会修改std::vector大小并引发段错误?
列向量构造GMatrix时无关std::vector被篡改的内存问题
尝试用列向量集合创建GMatrix对象时,发现一个未被任何代码操作的std::vector被意外篡改:初始化大小为1的vector,在创建GMatrix后大小莫名变为0,进而触发段错误。仅当列向量的数量(矩阵列数)大于向量维度(矩阵行数)时,才会出现该异常。
精简后的测试代码如下:
#include "GMatrix.h" int main(int argc, char *argv[]) { GVector<4> temp1{std::array<float,4>{0,0,0,0}}; GVector<4> temp2{std::array<float,4>{0,0,0,0}}; GVector<4> temp3{std::array<float,4>{0,0,0,0}}; GVector<4> temp4{std::array<float,4>{0,0,0,0}}; GVector<4> temp5{std::array<float,4>{0,0,0,0}}; std::array<GVector<4>,5> myArray{temp1,temp2,temp3,temp4,temp5}; //仅当向量数量大于向量维度时才会出现此异常行为 std::vector<int> problem(1); //未使用的大小为1的vector printf("%d-",problem.size()); // 输出1- GMatrix<4,myArray.size()> desiredMat{myArray}; printf("%d-",problem.size()); // 莫名输出0- printf("%d-",problem[0]); //因problem大小为0,此处触发段错误 return 0; }
GMatrix实现代码:
#include <array> #include <vector> #include <stdexcept> #include "GVector.h" template <size_t R, size_t C> class GMatrix { public: std::array<float,R*C> data; //零矩阵 GMatrix() : data{}{} GMatrix(std::array<float,R*C> matrixData){ data = matrixData; } //通过列向量构造矩阵 GMatrix(std::array<GVector<R>,C> vectors) : data{}{ for (int i=0;i<C;i++) { //遍历每个向量 for (int crd=0;crd<R;crd++) { //遍历每个坐标 this->data[i*C + crd] = vectors[i].data[crd]; } } } };
注意:矩阵以一维数组形式存储,而非常规的二维形式。例如,第2行第1列的元素索引为
[2*(列数)+1]
GVector实现代码:
#include <array> #include <stdexcept> template <size_t T> class GVector { public: std::array<float,T> data; GVector() : data{}{} GVector(std::array<float,T> given) { this->data = given; } float& operator[](size_t index) { if(index>=T){ std::out_of_range e("Index out of range"); throw e; } return data[index]; } };
问题原因
问题出在GMatrix的列向量构造函数中,数组索引计算错误导致内存越界写入:
构造函数中使用i*C + crd作为data数组的索引,其中:
i是列索引(0到C-1)C是矩阵的列数crd是行索引(0到R-1)
当C > R时(比如测试代码中R=4,C=5),索引的最大值为(C-1)*C + (R-1),即4*5+3=23,但GMatrix的data数组大小是R*C=20,这意味着索引超出了数组的有效范围,会写入到数组之外的内存区域。而栈上的problem向量恰好位于该越界区域附近,因此其内部数据(包括记录大小的成员)被篡改,导致size变为0,最终触发段错误。
根据你标注的存储规则(第2行第1列元素索引为2*C +1),正确的索引计算应该是行索引×列数 + 列索引,也就是crd*C + i,而不是i*C + crd。
修复方案
修改GMatrix的列向量构造函数中的索引计算逻辑:
//通过列向量构造矩阵 GMatrix(std::array<GVector<R>,C> vectors) : data{}{ for (int i=0;i<C;i++) { //遍历每个列向量 for (int crd=0;crd<R;crd++) { //遍历向量的每个行元素 this->data[crd*C + i] = vectors[i].data[crd]; } } }
修改后,索引的最大值为(R-1)*C + (C-1),即3*5+4=19,刚好等于R*C-1=20-1=19,不会超出data数组的有效范围,也就不会篡改其他变量的内存。
内容的提问来源于stack exchange,提问作者stackuser
相关产品推荐
相关产品推荐

