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

vector用emplace_back创建对象致map中对应指针属性数据丢失

问题:vector存储Product对象后,map存指针出现std::bad_alloc与数据覆盖问题

从CSV文件读取数据创建Product对象存入std::vector,同时将对象指针以Product ID为键存入std::map,运行时出现std::bad_alloc错误,且打印map中对象属性时数据乱码。调试发现创建第二个Product对象时,map中前一个对象的属性数据被清除。尝试替换emplace_back为push_back、拆分循环等方法均未解决问题。

原因分析

  1. vector内存重分配导致指针失效
    std::vector在容量不足时,会自动重新分配更大的内存空间,并将原有元素拷贝到新内存中,原有元素的地址会失效。代码中每次调用products.emplace_back后,将&products.back()存入map,当vector触发内存重分配时,之前存入map的指针就变成了野指针,访问这些指针会导致数据乱码、内存访问错误,最终触发std::bad_alloc。

  2. 拆分循环时的临时变量指针问题
    拆分循环的写法中,for (auto product : products)是对vector中元素的值拷贝,每次循环的product是临时变量,取&product存入map后,循环结束临时变量销毁,map中的指针全部指向已释放的内存,同样会导致非法内存访问。

解决方案

方案1:提前预留vector容量,避免内存重分配

在创建products后,调用reserve方法提前分配足够的内存,确保后续emplace_back不会触发内存重分配,指针地址保持有效:

std::map<std::string, Product*> loadProductMap(std::string fileName) {
    std::vector<std::vector<std::string>> productMapFile = Reader::readCSV(fileName);
    std::vector<Product> products;
    // 提前预留足够容量,避免内存重分配
    products.reserve(productMapFile.size());
    std::map<std::string, Product*> productMap;
    for (size_t i = 0; i < productMapFile.size(); i++) {
        products.emplace_back(productMapFile.at(i).at(0), productMapFile.at(i).at(1), stod(productMapFile.at(i).at(2)));
        productMap.emplace(products.at(i).getProductID(), &products.at(i));
    }
    return productMap;
}

方案2:使用智能指针管理内存(推荐)

改用std::unique_ptr或std::shared_ptr存储对象,避免手动管理指针的生命周期,彻底消除野指针问题:

#include <memory> // 需包含头文件

std::map<std::string, std::unique_ptr<Product>> loadProductMap(std::string fileName) {
    std::vector<std::vector<std::string>> productMapFile = Reader::readCSV(fileName);
    std::map<std::string, std::unique_ptr<Product>> productMap;
    for (auto& row : productMapFile) {
        // 直接在map中创建智能指针管理的Product对象
        productMap.emplace(row[0], std::make_unique<Product>(row[0], row[1], stod(row[2])));
    }
    return productMap;
}

// main函数中遍历方式调整
int main() {
    auto productMap = loadProductMap("product_list.csv");
    for (auto& i : productMap) {
        std::cout << i.second->getProductID() << " " 
                  << i.second->getProductName() << " " 
                  << i.second->getProductPrice() << std::endl;
    }
    return 0;
}

方案3:map直接存储Product对象,避免指针

如果不需要共享对象,直接让map存储Product对象副本,代码更简洁安全:

std::map<std::string, Product> loadProductMap(std::string fileName) {
    std::vector<std::vector<std::string>> productMapFile = Reader::readCSV(fileName);
    std::map<std::string, Product> productMap;
    for (auto& row : productMapFile) {
        productMap.emplace(row[0], Product(row[0], row[1], stod(row[2])));
    }
    return productMap;
}

// main函数中遍历方式调整
int main() {
    auto productMap = loadProductMap("product_list.csv");
    for (auto& i : productMap) {
        std::cout << i.second.getProductID() << " " 
                  << i.second.getProductName() << " " 
                  << i.second.getProductPrice() << std::endl;
    }
    return 0;
}

补充说明

  • 方案1仅适用于vector后续不会再触发内存重分配的场景,若后续仍有添加元素操作,仍可能出现指针失效问题;
  • 方案2和方案3从根本上避免了野指针问题,是更健壮的实现方式,其中方案2适合需要共享对象的场景,方案3适合简单存储的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 01:45:09