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

C++中向map添加对象时地址变化问题求助

问题原因及解决办法

你的核心问题在于std::map的存储机制和对象拷贝规则:

  1. 地址不同的原因
    假设exits是std::map<std::string, Item>类型,它存储的是Item对象的完整拷贝,而非引用或指针。当执行this->exits[key] = item;时,程序会调用Item的赋值运算符(默认或自定义),把传入的item复制一份存入map的内部内存空间。因此你打印的两个地址分别对应:

    • 原传入的item对象的内存地址
    • map中新建的拷贝对象的内存地址
      二者自然不同。
  2. 存入后方法失效的原因
    调用map中对象的方法失效,几乎可以肯定是Item类存在浅拷贝问题。如果Item内部包含动态分配的资源(比如裸指针、非智能指针的动态内存),C++默认的拷贝构造/赋值运算符只会复制成员变量的表面值,不会复制指针指向的底层资源。当原item对象被销毁后,map里的拷贝对象的指针就会变成野指针,调用方法时必然出错。


解决办法

方法一:让map存储指针/智能指针

如果希望直接使用原对象,让map存储指针或智能指针,这样存入的是原对象的地址,前后打印的地址会一致:

  • 存储原始指针(注意对象生命周期管理):

    // 先修改Room类中exits的定义:
    std::map<std::string, const Item*> exits;
    
    // 然后修改AddExit函数:
    void Room::AddExit(const std::string key, const Item& item){
        std::cout << "Location before: " << &item << std::endl;
        this->exits[key] = &item;
        std::cout << "Location after: " << this->exits[key] << std::endl;
    }
    

    注意:必须保证传入的item生命周期长于Room对象,否则会出现悬空指针。

  • 存储智能指针(推荐,自动管理生命周期):

    // 修改Room类中exits的定义:
    std::map<std::string, std::shared_ptr<Item>> exits;
    
    // 修改AddExit函数:
    void Room::AddExit(const std::string key, std::shared_ptr<Item> item){
        std::cout << "Location before: " << item.get() << std::endl;
        this->exits[key] = item;
        std::cout << "Location after: " << this->exits[key].get() << std::endl;
    }
    

方法二:实现深拷贝

如果必须让map存储对象本身,需要为Item类手动实现拷贝构造函数和赋值运算符重载,确保内部动态资源被正确复制:

class Item {
private:
    char* m_data; // 假设存在动态分配的指针成员
public:
    // 拷贝构造函数
    Item(const Item& other) {
        // 复制长度并分配新内存
        size_t len = strlen(other.m_data);
        m_data = new char[len + 1];
        strcpy(m_data, other.m_data);
    }

    // 赋值运算符重载
    Item& operator=(const Item& other) {
        if (this != &other) { // 防止自赋值
            // 释放当前对象的资源
            delete[] m_data;
            // 复制新资源
            size_t len = strlen(other.m_data);
            m_data = new char[len + 1];
            strcpy(m_data, other.m_data);
        }
        return *this;
    }

    // 析构函数释放资源
    ~Item() {
        delete[] m_data;
    }
};

这样拷贝后的对象拥有独立的资源,即使原对象被销毁,map中的对象也能正常工作。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 09:07:46