如何用std::shared_ptr共享非连续的内存区间?
实现非连续内存区间的共享方案
std::shared_ptr本身设计用于管理单一连续内存块(或单个对象),没法直接让它同时管理多个非连续的内存区间,这也是你遇到“无法获取float*类型右值的地址”报错的根本原因——它只接受单个原始指针关联控制块,无法绑定分散的多段指针。
下面是几种可行的实现思路:
1. 用多个shared_ptr分别管理各连续段
非连续区间本质是多个连续子段的组合,直接为每个子段创建独立的shared_ptr,通过捕获原数组的shared_ptr来共享所有权,避免原内存提前释放。示例代码:
#include <memory> #include <vector> int main() { auto arr = std::make_shared<std::vector<float>>(100); // 原数组 auto& vals = *arr; // 管理索引2-5的连续段(长度4) std::shared_ptr<float> seg1(vals.data() + 2, [arr](float*){}); // 管理索引70至末尾的连续段(长度30) std::shared_ptr<float> seg2(vals.data() + 70, [arr](float*){}); // 使用seg1和seg2访问对应区间,原数组生命周期由所有shared_ptr共同维护 return 0; }
这里的自定义删除器为空逻辑,因为原数组的销毁权已经交给arr,只要seg1或seg2存在,arr的引用计数就不会归零,原数组不会被释放。
2. 自定义视图类封装非连续区间
如果需要对外提供统一的数组式访问接口,可以编写自定义视图类,内部持有原数组的shared_ptr,同时保存各非连续段的起始索引和长度,对外屏蔽非连续的细节:
#include <memory> #include <vector> #include <stdexcept> struct NonContiguousView { using ElementType = float; std::shared_ptr<std::vector<ElementType>> arr; std::vector<std::pair<size_t, size_t>> segments; // 每个元素为(起始索引, 段长度) // 构造函数:传入原数组shared_ptr和非连续段范围 NonContiguousView(std::shared_ptr<std::vector<ElementType>> ptr, std::initializer_list<std::pair<size_t, size_t>> segs) : arr(std::move(ptr)) { for (auto& seg : segs) { if (seg.first + seg.second > arr->size()) { throw std::out_of_range("Segment exceeds array bounds"); } segments.push_back(seg); } } // 按拼接顺序访问第n个元素 ElementType& operator[](size_t n) { size_t total = 0; for (auto& seg : segments) { if (n < total + seg.second) { return (*arr)[seg.first + (n - total)]; } total += seg.second; } throw std::out_of_range("Index out of view bounds"); } // 获取视图总元素数 size_t size() const { size_t s = 0; for (auto& seg : segments) s += seg.second; return s; } }; int main() { auto arr = std::make_shared<std::vector<float>>(100); // 创建视图:包含索引2-5(长度4)和70-99(长度30)的区间 NonContiguousView view(arr, {{2,4}, {70,30}}); // 像访问普通数组一样操作视图 view[0] = 1.0f; // 对应原数组索引2 view[3] = 2.0f; // 对应原数组索引5 view[4] = 3.0f; // 对应原数组索引70 return 0; }
3. 核心注意事项
- 不要尝试让单个shared_ptr绑定多个分散指针,这违背它的设计逻辑,会导致内存管理混乱。
- 无论用哪种方案,都要确保原数组的生命周期被正确维护,避免出现野指针。
内容的提问来源于stack exchange,提问作者Sam Moldenha
相关产品推荐
相关产品推荐

