C++中向map添加对象时地址变化问题求助
问题原因及解决办法
你的核心问题在于std::map的存储机制和对象拷贝规则:
地址不同的原因
假设exits是std::map<std::string, Item>类型,它存储的是Item对象的完整拷贝,而非引用或指针。当执行this->exits[key] = item;时,程序会调用Item的赋值运算符(默认或自定义),把传入的item复制一份存入map的内部内存空间。因此你打印的两个地址分别对应:- 原传入的
item对象的内存地址 - map中新建的拷贝对象的内存地址
二者自然不同。
- 原传入的
存入后方法失效的原因
调用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
相关产品推荐
相关产品推荐

