C++中类指针存入map的内存泄漏问题及智能指针解决方案
问题解答
1. 内存泄漏问题
这段代码会明确导致内存泄漏。你通过new手动分配了10个Person对象的堆内存,但全程没有调用delete释放这些内存。虽然程序退出后操作系统会回收进程占用的所有内存,但从C++标准和内存管理规范来说,这属于典型的内存泄漏场景——如果是长期运行的服务类程序,这类泄漏会持续消耗系统内存,最终引发性能问题甚至崩溃。
2. 用智能指针解决内存泄漏
使用C++标准库的智能指针可以自动管理内存,无需手动调用delete,推荐用std::unique_ptr(因为std::map是这些Person对象的唯一所有者,独占所有权更高效),也可以根据需求用std::shared_ptr(适用于多所有者场景)。
基于std::unique_ptr的实现
#include <iostream> #include <map> #include <memory> #include <string> class Person { private: int m_age; std::string m_name; public: Person(int age, std::string name): m_age(age), m_name(std::move(name)) // 用move避免字符串拷贝,优化性能 {} void PrintPerson() const // 成员函数加const,符合const正确性 { std::cout << "name: " << m_name << "\n"; std::cout << "age: " << m_age << "\n"; } }; int main() { // 用unique_ptr作为map的值类型 std::map<size_t, std::unique_ptr<Person>> person_map; for (int n = 0; n < 10; ++n) { // 用make_unique创建unique_ptr,避免直接用new person_map.emplace(n, std::make_unique<Person>(n, std::to_string(n))); } for (const auto& pair : person_map) { pair.second->PrintPerson(); } // 无需手动delete,map销毁时会自动释放所有unique_ptr管理的内存 return 0; }
补充:直接存储对象(更简单的方案)
如果Person类的拷贝/移动开销不大(比如示例中只有int和string,移动成本很低),直接在std::map中存储Person对象是更简洁的选择,完全不需要指针:
#include <iostream> #include <map> #include <string> class Person { private: int m_age; std::string m_name; public: Person(int age, std::string name): m_age(age), m_name(std::move(name)) {} void PrintPerson() const { std::cout << "name: " << m_name << "\n"; std::cout << "age: " << m_age << "\n"; } }; int main() { std::map<size_t, Person> person_map; for (int n = 0; n < 10; ++n) { // emplace直接在map中构造对象,避免额外拷贝 person_map.emplace(n, n, std::to_string(n)); } for (const auto& pair : person_map) { pair.second.PrintPerson(); } return 0; }
3. 手动管理内存的正确方式(不推荐)
如果一定要用裸指针,必须在程序结束前手动遍历map并delete每个对象,同时要注意异常安全(比如如果delete前程序抛出异常,会跳过释放逻辑):
int main() { std::map<size_t, Person*> person_map; for (int n = 0; n < 10; ++n) { person_map.insert(std::make_pair(n, new Person(n, std::to_string(n)))); } for (int n = 0; n < 10; ++n) { person_map.at(n)->PrintPerson(); } // 手动释放所有对象内存 for (auto& pair : person_map) { delete pair.second; } return 0; }
这种方式容易出错,因此强烈建议优先使用智能指针或直接存储对象的方案。
内容的提问来源于stack exchange,提问作者Nick X Tsui
相关产品推荐
相关产品推荐

