跳转到内容

C++ 智能指针与容器

来自代码酷


概述[编辑 | 编辑源代码]

C++智能指针是一种自动管理动态内存的RAII(Resource Acquisition Is Initialization)对象,而容器是存储和管理对象集合的数据结构。将智能指针与标准库容器结合使用,可以安全高效地处理动态分配对象的生命周期问题,避免内存泄漏和悬空指针等问题。

智能指针主要包括:

  • std::unique_ptr(独占所有权)
  • std::shared_ptr(共享所有权)
  • std::weak_ptr(避免循环引用)

智能指针与容器的结合[编辑 | 编辑源代码]

为什么需要结合使用?[编辑 | 编辑源代码]

容器(如std::vectorstd::map)通常存储原始指针时需手动释放内存,而智能指针能自动释放资源。结合使用可:

  • 简化内存管理
  • 避免容器元素的内存泄漏
  • 支持异常安全

基本用法示例[编辑 | 编辑源代码]

以下示例展示std::vectorstd::unique_ptr的结合:

#include <iostream>
#include <memory>
#include <vector>

class MyClass {
public:
    MyClass(int val) : value(val) {
        std::cout << "Constructed: " << value << std::endl;
    }
    ~MyClass() {
        std::cout << "Destroyed: " << value << std::endl;
    }
    void print() const { std::cout << "Value: " << value << std::endl; }
private:
    int value;
};

int main() {
    std::vector<std::unique_ptr<MyClass>> vec;
    
    // 添加元素
    vec.push_back(std::make_unique<MyClass>(10));
    vec.push_back(std::make_unique<MyClass>(20));
    
    // 访问元素
    for (const auto& ptr : vec) {
        ptr->print();
    }
    
    // 自动释放内存
    return 0;
}

输出:

Constructed: 10
Constructed: 20
Value: 10
Value: 20
Destroyed: 20
Destroyed: 10

所有权转移问题[编辑 | 编辑源代码]

std::unique_ptr不可复制,但可通过移动语义转移所有权:

std::vector<std::unique_ptr<MyClass>> vec1;
auto ptr = std::make_unique<MyClass>(30);
vec1.push_back(std::move(ptr));  // 所有权转移

高级应用场景[编辑 | 编辑源代码]

共享所有权的容器[编辑 | 编辑源代码]

当需要多个容器共享对象时,使用std::shared_ptr

std::vector<std::shared_ptr<MyClass>> sharedVec1;
std::vector<std::shared_ptr<MyClass>> sharedVec2;
auto sharedObj = std::make_shared<MyClass>(99);

sharedVec1.push_back(sharedObj);
sharedVec2.push_back(sharedObj);  // 共享所有权

避免循环引用[编辑 | 编辑源代码]

使用std::weak_ptr打破循环引用:

struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev;  // 避免循环引用
};

性能考量[编辑 | 编辑源代码]

内存开销对比[编辑 | 编辑源代码]

智能指针内存开销
类型 额外开销
std::unique_ptr 无(仅存储指针)
std::shared_ptr 控制块(引用计数等)
std::weak_ptr shared_ptr

容器选择建议[编辑 | 编辑源代码]

  • 优先使用std::unique_ptr(性能最优)
  • 需要共享时再用std::shared_ptr
  • 关联容器(如std::map)的键避免用智能指针

实际案例[编辑 | 编辑源代码]

场景:对象池管理[编辑 | 编辑源代码]

使用std::vector<std::unique_ptr<Texture>>管理游戏资源:

class TexturePool {
private:
    std::vector<std::unique_ptr<Texture>> textures;
public:
    void load(const std::string& path) {
        textures.push_back(std::make_unique<Texture>(path));
    }
    // 其他管理接口...
};

场景:多线程安全共享[编辑 | 编辑源代码]

线程安全的共享数据容器:

std::vector<std::shared_ptr<const Data>> getSnapshot() {
    std::lock_guard<std::mutex> lock(dataMutex);
    return currentData;  // 返回共享数据的副本
}

常见问题[编辑 | 编辑源代码]

Q1: 能否在容器中存储auto_ptr[编辑 | 编辑源代码]

页面模块:Message box/ambox.css没有内容。

Q2: 如何排序智能指针容器?[编辑 | 编辑源代码]

提供自定义比较器:

std::sort(vec.begin(), vec.end(), 
    [](const std::unique_ptr<MyClass>& a, const std::unique_ptr<MyClass>& b) {
        return a->value < b->value;
    });

总结[编辑 | 编辑源代码]

  • 优先选择std::unique_ptr + 容器组合
  • 共享所有权时使用std::shared_ptr
  • 注意容器的操作可能影响智能指针的生命周期

graph LR A[原始指针容器] -->|问题| B(内存泄漏风险) A -->|问题| C(异常不安全) D[智能指针容器] -->|解决| B D -->|解决| C