You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何无关代码会修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 16:47:14