当前位置: 首页 > article >正文

C++ STL <memory>

C++标准库中的<memory>头文件提供了一组与动态内存管理相关的工具,包括智能指针、内存分配器、对象构造与销毁的辅助工具等。这些工具极大地简化了动态内存管理,并提高了代码的安全性和可维护性。


1. <memory>概述

主要内容

<memory>头文件主要包括以下内容:

  1. 智能指针std::shared_ptrstd::unique_ptrstd::weak_ptr
  2. 内存管理工具std::allocatorstd::uninitialized_*函数。
  3. 对象构造和销毁工具std::construct_atstd::destroy_at等。
  4. 其他工具:如std::addressofstd::pointer_traits

头文件

#include <memory>

2. 智能指针

智能指针是<memory>中最常用的工具,主要解决动态内存管理中的资源泄漏问题。


2.1 std::shared_ptr

std::shared_ptr是一个共享所有权的智能指针,多个shared_ptr可以共享同一个对象。当最后一个shared_ptr被销毁时,所管理的对象会被自动释放。

主要功能
  • 自动管理动态内存,避免手动释放。
  • 使用引用计数管理对象的生命周期。
常用函数
  • use_count():返回当前引用计数。
  • reset():释放当前对象的控制权。
  • get():返回原始指针。
  • make_shared:创建shared_ptr的推荐方式。
示例
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sp1 = std::make_shared<int>(10);
    std::shared_ptr<int> sp2 = sp1; // 引用计数+1

    std::cout << "Value: " << *sp1 << ", Use count: " << sp1.use_count() << "\n";

    sp2.reset(); // sp2释放控制权
    std::cout << "Use count after reset: " << sp1.use_count() << "\n";

    return 0;
}

运行结果

Value: 10, Use count: 2
Use count after reset: 1

2.2 std::unique_ptr

std::unique_ptr是一个独占所有权的智能指针,保证一个unique_ptr对象只能管理一个动态分配的对象。

主要功能
  • 独占所有权,不能被复制(支持移动)。
  • 更轻量级,适合不需要共享的场景。
常用函数
  • release():释放控制权并返回原始指针。
  • reset():释放当前对象并管理新对象。
  • get():返回原始指针。
  • make_unique:创建unique_ptr的推荐方式。
示例
#include <iostream>
#include <memory>

int main() {
    std::unique_ptr<int> up = std::make_unique<int>(20);
    std::cout << "Value: " << *up << "\n";

    std::unique_ptr<int> up2 = std::move(up); // 转移所有权
    if (!up) {
        std::cout << "up is null after move.\n";
    }

    return 0;
}

运行结果

Value: 20
up is null after move.

2.3 std::weak_ptr

std::weak_ptr是一个非拥有型指针,用于解决std::shared_ptr的循环引用问题。

主要功能
  • 不影响共享对象的引用计数。
  • 可用于检查shared_ptr所管理的对象是否仍然存在。
常用函数
  • lock():返回一个指向共享对象的shared_ptr
  • expired():检查所管理的对象是否已销毁。
  • use_count():返回共享对象的引用计数。
示例
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sp = std::make_shared<int>(30);
    std::weak_ptr<int> wp = sp;

    std::cout << "Use count: " << wp.use_count() << "\n";

    if (auto sp2 = wp.lock()) { // 检查对象是否仍然存在
        std::cout << "Value: " << *sp2 << "\n";
    }

    sp.reset(); // 销毁共享对象
    if (wp.expired()) {
        std::cout << "Object expired.\n";
    }

    return 0;
}
Use count: 1    #不影响共享对象的引用计数
Value: 30

wp.expired():检查wp所关联的对象是否已经被销毁。由于sp2仍然持有对象的引用,所以对象尚未被销毁,wp.expired()返回false,不会输出Object expired.。


3. 内存管理工具

3.1 std::allocator

std::allocator是C++标准库的默认内存分配器,用于容器的动态内存分配。

主要功能
  • 提供内存的分配和释放。
  • 提供对象的构造与销毁。
常用函数
  • allocate():分配内存。
  • deallocate():释放内存。
  • construct():构造对象(C++17后已弃用)。
  • destroy():销毁对象(C++17后已弃用)。
示例
#include <iostream>
#include <memory>

int main() {
    std::allocator<int> alloc;

    int* p = alloc.allocate(3); // 分配3个int的内存
    alloc.construct(p, 42);     // 在p处构造一个值为42的int

    std::cout << "Value: " << *p << "\n";

    alloc.destroy(p);           // 销毁对象
    alloc.deallocate(p, 3);     // 释放内存

    return 0;
}

3.2 std::uninitialized_* 系列函数

这些函数用于在未初始化的内存中构造对象,常用于性能优化。

主要函数
  • std::uninitialized_copy:在未初始化的内存中复制元素。
  • std::uninitialized_fill:在未初始化的内存中填充元素。
  • std::uninitialized_move:在未初始化的内存中移动元素。
示例
#include <iostream>
#include <memory>
#include <vector>

int main() {
    std::vector<int> src = {1, 2, 3};
    int* dest = static_cast<int*>(operator new[](src.size() * sizeof(int)));

    std::uninitialized_copy(src.begin(), src.end(), dest);

    for (size_t i = 0; i < src.size(); ++i) {
        std::cout << dest[i] << " ";
    }

    std::destroy(dest, dest + src.size());
    operator delete[](dest);

    return 0;
}

4. 对象构造与销毁工具

4.1 std::construct_atstd::destroy_at

std::construct_at

在指定内存地址上构造对象。

std::destroy_at

销毁指定地址上的对象。

示例
#include <iostream>
#include <memory>

int main() {
    alignas(int) char buffer[sizeof(int)];
    int* p = reinterpret_cast<int*>(buffer);

    std::construct_at(p, 42); // 在buffer处构造int对象
    std::cout << "Value: " << *p << "\n";

    std::destroy_at(p);       // 销毁对象

    return 0;
}

5. 其他工具

5.1 std::addressof

std::addressof用于获取对象的真实地址,避免被重载的operator&干扰。

示例
#include <iostream>
#include <memory>

struct Example {
    int operator&() { return 42; }
};

int main() {
    Example e;
    std::cout << "Address: " << std::addressof(e) << "\n"; // 获取真实地址
    return 0;
}

5.2 std::pointer_traits

std::pointer_traits是一个模板类,用于获取指针类型的相关信息。


6. 注意事项

  1. 智能指针的循环引用

    • 避免std::shared_ptr之间的循环引用,使用std::weak_ptr解决。
  2. std::unique_ptr的所有权

    • 不能复制std::unique_ptr,只能通过std::move转移所有权。
  3. 内存泄漏

    • 确保动态分配的内存被正确释放,智能指针可以显著减少此类问题。
  4. 性能优化

    • 使用std::make_sharedstd::make_unique可以减少内存分配的开销。

全力以赴度过今天,自然就能看清楚明天。 —稻盛和夫


http://www.kler.cn/a/571041.html

相关文章:

  • Metal学习笔记十:光照基础
  • KVM虚拟机磁盘创建探究-2
  • 基于大数据的北京二手房房价信息预测可视化分析系统
  • 如何停止Oracle expdp/impdp job
  • 智能家居:DeepSeek在家庭自动化中的创新应用
  • 基于普通嵌入式交叉编译QT5.12.x系列
  • centos虚拟机安装
  • 芯麦GC1262E:电脑散热风扇驱动芯片的优质之选并可替代传统的APX9262S茂达芯片
  • 后端 PDF 生成方案(OpenPDF + Thymeleaf)
  • DApp开发中的模式设计、功能文档与代币对接解析
  • 【深度学习】—— Keras快速入门
  • rust学习笔记7-344. 反转字符串
  • 大疆机场3发布:车载移动部署新突破,无人机技术再升级
  • FPGA开发,使用Deepseek V3还是R1(6):以滤波器为例
  • OpenHarmony启动恢复子系统
  • 机器学习的起点:线性回归Linear Regression
  • Linux知识-第一天
  • 【音视频】H265解码Nalu后封装rtp包
  • AI应用开发 3 - prompt 提示词工程
  • Grafana服务安装并启动