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

使用std::sort排序需深拷贝的结构体时触发内存异常的解决咨询

问题描述

定义了继承自gsk_oid的oidX结构体,以及包含oidX*成员的oidPair结构体,创建oidPair数组后调用std::sort排序时触发内存异常,第三次调用Oid_less比较函数时,right参数引用的oidPair包含未初始化的oidX指针。

相关代码如下:

基础结构体定义

typedef unsigned int    gsk_uint32;
typedef struct _gsk_oid {
    int                 count;
    gsk_uint32 *        elements;
} gsk_oid;

struct oidX : public gsk_oid
{
    oidX();     // 默认构造函数
    oidX(int countX, gsk_uint32 first, ...);        // 从整数列表构造
    oidX(const char* oidString);        // 从点分符号构造
    oidX(const gsk_oid *inOID);     // 从gsk_oid构造
    ~oidX();        // 析构函数
};

oidPair结构体定义

struct oidPair {
    oidX *TheOID;
    const char *Descript;
    oidPair(oidX *inputOID, const char *inputDescript); 
    ~oidPair();
};

数组初始化与排序调用

oidPair testOIDs[4] = {
    oidPair(new oidX("2.23.140.1.2.3"), "Certificates issued in accordance with the CA/Browser Forum's Baseline Requirements - Individual identity asserted"),
    oidPair(new oidX("2.23.140.1.1"), "Extended Validation (EV) guidelines certificate policy"),
    oidPair(new oidX("1.3.6.1.4.1.4146.1.20"), "Organization validation certificate policy"),
    oidPair(new oidX("2.23.140.1.2.2"), "Certificates issued in accordance with the CA/Browser Forum's Baseline Requirements - Organization identity asserted") };

std::sort(testOIDs, testOIDs+4, &Oid_less);

比较函数实现

int DecodeOID::Oid_cmp(const gsk_oid *left, const gsk_oid *right)
{
    int cnt = std::min(left->count, right->count);      // 取两个向量中较短的长度
    int ret = memcmp(left->elements, right->elements, cnt*4); // 比较元素
    if ( 0 != ret ) return ret;  // 若不相等则返回结果
    return left->count - right->count;      // 否则较长的视为更大
}

bool DecodeOID::Oid_less(const oidPair &left, const oidPair &right)
{
    const gsk_oid *l = left.TheOID;
    const gsk_oid *r = right.TheOID;
    int ret = Oid_cmp(l, r);
    return ret < 0;
}
问题根源

std::sort在排序过程中需要对数组元素进行拷贝、移动或交换操作,但oidPair仅定义了构造函数和析构函数,没有实现拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符。编译器生成的默认版本是浅拷贝,会直接复制TheOID指针,导致多个oidPair对象指向同一个oidX实例,析构时重复释放内存;同时,排序过程中创建临时对象时,默认操作可能导致指针未初始化,最终触发内存访问异常。

解决方案

有两种可行方案,推荐优先使用智能指针方案,避免手动内存管理错误。

方案一:手动实现三/五法则

为oidPair实现完整的拷贝、移动操作,确保指针成员的正确管理:

struct oidPair {
    oidX *TheOID;
    const char *Descript;

    // 构造函数
    oidPair(oidX *inputOID, const char *inputDescript) 
        : TheOID(inputOID), Descript(inputDescript) {}

    // 拷贝构造:深拷贝oidX实例
    oidPair(const oidPair& other) 
        : TheOID(new oidX(other.TheOID)), Descript(other.Descript) {}

    // 移动构造:接管原对象的指针,避免深拷贝
    oidPair(oidPair&& other) noexcept 
        : TheOID(other.TheOID), Descript(other.Descript) {
        other.TheOID = nullptr; // 原对象放弃指针所有权
    }

    // 拷贝赋值运算符
    oidPair& operator=(const oidPair& other) {
        if (this != &other) { // 避免自我赋值
            delete TheOID; // 释放当前指针
            TheOID = new oidX(other.TheOID); // 深拷贝新对象
            Descript = other.Descript;
        }
        return *this;
    }

    // 移动赋值运算符
    oidPair& operator=(oidPair&& other) noexcept {
        if (this != &other) {
            delete TheOID;
            TheOID = other.TheOID;
            Descript = other.Descript;
            other.TheOID = nullptr;
        }
        return *this;
    }

    // 析构函数
    ~oidPair() {
        delete TheOID;
    }
};

注意:需确保oidX的拷贝构造函数正确深拷贝elements数组,示例如下:

oidX::oidX(const gsk_oid *inOID) {
    count = inOID->count;
    elements = new gsk_uint32[count];
    std::memcpy(elements, inOID->elements, count * sizeof(gsk_uint32));
}

oidX::oidX(const oidX& other) {
    count = other.count;
    elements = new gsk_uint32[count];
    std::memcpy(elements, other.elements, count * sizeof(gsk_uint32));
}

方案二:使用智能指针(推荐)

用std::unique_ptr替换裸指针,让智能指针自动管理内存,无需手动实现拷贝/移动函数:

#include <memory>

struct oidPair {
    std::unique_ptr<oidX> TheOID;
    const char *Descript;

    // 构造函数:接收移动后的unique_ptr
    oidPair(std::unique_ptr<oidX> inputOID, const char *inputDescript) 
        : TheOID(std::move(inputOID)), Descript(inputDescript) {}

    // 无需手动实现析构、拷贝/移动函数,编译器自动生成正确逻辑
};

// 数组初始化写法调整
oidPair testOIDs[4] = {
    oidPair(std::make_unique<oidX>("2.23.140.1.2.3"), "Certificates issued in accordance with the CA/Browser Forum's Baseline Requirements - Individual identity asserted"),
    oidPair(std::make_unique<oidX>("2.23.140.1.1"), "Extended Validation (EV) guidelines certificate policy"),
    oidPair(std::make_unique<oidX>("1.3.6.1.4.1.4146.1.20"), "Organization validation certificate policy"),
    oidPair(std::make_unique<oidX>("2.23.140.1.2.2"), "Certificates issued in accordance with the CA/Browser Forum's Baseline Requirements - Organization identity asserted")
};

std::unique_ptr是独占所有权的智能指针,排序过程中会自动移动指针,避免浅拷贝问题,同时自动释放内存,彻底消除手动管理内存的风险。


内容的提问来源于stack exchange,提问作者Charles

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:15:57