You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何存储数量可变且不可默认构造、复制、移动的对象?

问题:存储不可移动/复制、非默认构造的运行时数量对象

我需要一块连续内存存储运行时才知晓数量的Data对象,但这些对象:

  • 不可默认构造
  • 不可复制、不可移动(因持有资源和外部内存引用,且我希望显式禁用这些操作避免误操作)

背景:开发数据处理程序,程序启动初期输入会指定Data对象的创建数量,每个Data持有资源并引用输入对象的内存,运行时需要反复遍历这些对象执行任务。

原本用std::vector预留内存后调用emplace_back实现连续存储,但为调试添加Data析构函数后,std::vector依赖的移动构造函数被隐式删除,导致编译失败。实际上这些移动构造函数从未被调用过,只是生成了无用的二进制代码,我更倾向于直接删除这些操作符。

试过的方案:

  • 若Data可默认构造并后续设置输入指针,可使用std::unique_ptr<Data[]>,但目前Data无法默认构造
  • 尝试过eastl::fixed_vector,但它需要编译时指定容量,且要求对象可移动

方案1:手动管理内存 + std::aligned_storage

直接控制原始内存,手动构造/析构对象,完全规避复制/移动需求,确保对象连续存储。

代码示例

#include <memory>
#include <type_traits>

class Input {}; // 示例输入类

class Data {
public:
    explicit Data(const Input& input) : input_(&input) {}
    ~Data() = default;

    // 显式禁用复制、移动操作
    Data(const Data&) = delete;
    Data& operator=(const Data&) = delete;
    Data(Data&&) = delete;
    Data& operator=(Data&&) = delete;

    // 业务处理方法
    void process() {}

private:
    const Input* input_;
    // 其他资源成员
};

// 自定义连续存储容器
class DataBuffer {
public:
    DataBuffer(size_t count, const Input& input)
        : storage_(std::make_unique<std::aligned_storage_t<sizeof(Data), alignof(Data)>[]>(count)),
          count_(count)
    {
        // 原地构造每个Data对象
        for (size_t i = 0; i < count_; ++i) {
            new (get_ptr(i)) Data(input);
        }
    }

    ~DataBuffer() {
        // 手动析构每个Data对象
        for (size_t i = 0; i < count_; ++i) {
            get_ptr(i)->~Data();
        }
    }

    // 禁用容器的复制/移动(可选,根据需求调整)
    DataBuffer(const DataBuffer&) = delete;
    DataBuffer& operator=(const DataBuffer&) = delete;
    DataBuffer(DataBuffer&&) = delete;
    DataBuffer& operator=(DataBuffer&&) = delete;

    // 随机访问接口
    Data& operator[](size_t idx) { return *get_ptr(idx); }
    const Data& operator[](size_t idx) const { return *get_ptr(idx); }

    // 迭代器支持(方便范围for遍历)
    Data* begin() { return get_ptr(0); }
    Data* end() { return get_ptr(count_); }
    const Data* begin() const { return get_ptr(0); }
    const Data* end() const { return get_ptr(count_); }

    size_t size() const { return count_; }

private:
    // 转换内存指针为Data对象指针
    Data* get_ptr(size_t idx) {
        return reinterpret_cast<Data*>(&storage_[idx]);
    }

    const Data* get_ptr(size_t idx) const {
        return reinterpret_cast<const Data*>(&storage_[idx]);
    }

    std::unique_ptr<std::aligned_storage_t<sizeof(Data), alignof(Data)>[]> storage_;
    size_t count_;
};

// 使用示例
int main() {
    Input input;
    const size_t data_count = 100; // 运行时确定的数量
    DataBuffer buffer(data_count, input);

    for (auto& data : buffer) {
        data.process();
    }
}

优缺点

  • 优点:完全控制内存布局,确保对象连续存储;无需Data支持复制/移动;运行时动态指定数量。
  • 缺点:需手动管理对象构造/析构,代码量略多;需自行实现容器基本功能(如迭代器)。

方案2:使用Boost容器库的boost::container::static_vector

若可引入Boost库,boost::container::static_vector支持运行时指定容量(非编译时固定),且在不扩容的场景下无需对象可移动。

代码示例

#include <boost/container/static_vector.hpp>

class Input {};
class Data { /* 同方案1,禁用复制移动 */ };

int main() {
    Input input;
    const size_t data_count = 100;
    // 0表示不限制编译时容量,运行时动态分配
    boost::container::static_vector<Data, 0> buffer;
    buffer.reserve(data_count);
    
    for (size_t i = 0; i < data_count; ++i) {
        buffer.emplace_back(input);
    }

    for (auto& data : buffer) {
        data.process();
    }
}

优缺点

  • 优点:自带容器的所有便利功能(迭代器、size、访问方法等);无需手动管理构造析构。
  • 缺点:依赖Boost库;若后续需扩容,仍要求对象可移动(但你的场景无需扩容)。

方案3:std::vector<std::unique_ptr<Data>>(妥协方案)

若可接受指针连续存储而非对象本身连续,此方案实现最简单,但对象实际存储在堆上,缓存友好性稍差。

代码示例

#include <vector>
#include <memory>

class Input {};
class Data { /* 同方案1,禁用复制移动 */ };

int main() {
    Input input;
    const size_t data_count = 100;
    std::vector<std::unique_ptr<Data>> buffer;
    buffer.reserve(data_count);

    for (size_t i = 0; i < data_count; ++i) {
        buffer.emplace_back(std::make_unique<Data>(input));
    }

    for (auto& data_ptr : buffer) {
        data_ptr->process();
    }
}

优缺点

  • 优点:实现最简单,无需额外代码;完全兼容Data的禁用复制移动。
  • 缺点:对象本身不连续,缓存命中率可能降低;多一层指针间接访问,性能略有损耗。

内容的提问来源于stack exchange,提问作者Lambo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:15:55