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

无法拷贝、移动且无默认构造的结构体堆分配方案咨询

问题描述

我定义了一个既无法拷贝、移动,也没有默认构造函数的结构体:

struct Data {
  int a;

  Data(const Data&) = delete;
  Data& operator=(const Data&) = delete;

  Data(Data&&) = delete;
  Data& operator=(Data&&) = delete;

  Data(int i):
    a{i}
  {}
};

我希望在堆上分配该结构体的数组,并使用同一个构造函数完成所有实例的初始化。目前我通过以下方式实现:

Data* ppd = (Data*)::operator new(10 * sizeof(Data));

for (auto p = ppd; p < ppd + 10; ++p)
  new(p) Data{45};

但我对这个实现并不满意,请问有没有更具表达性的实现方法?

解决方案

由于Data结构体禁用了拷贝、移动构造,且没有默认构造函数,无法通过批量拷贝的方式初始化数组,核心逻辑仍需基于分配原始内存+逐个构造,但可以借助C++标准库组件让代码更具表达性和规范性:

方法一:使用std::allocator(C++11及以上)

std::allocator是标准库提供的内存管理工具,封装了内存分配/释放和对象构造/销毁的细节,代码风格更符合现代C++:

#include <memory>

// 创建分配器实例
std::allocator<Data> alloc;
// 分配能容纳10个Data对象的内存
Data* ppd = alloc.allocate(10);

// 逐个构造Data对象,传入构造参数45
for (std::size_t i = 0; i < 10; ++i) {
    alloc.construct(ppd + i, 45);
}

// 注意:后续需要用allocator销毁对象并释放内存
// for (std::size_t i = 0; i < 10; ++i) {
//     alloc.destroy(ppd + i);
// }
// alloc.deallocate(ppd, 10);

方法二:使用std::construct_at配合范围迭代(C++20及以上)

C++20引入的std::construct_at可以替代placement new,配合范围库的迭代器让代码更简洁直观:

#include <memory>
#include <ranges>

// 分配原始内存
Data* ppd = static_cast<Data*>(::operator new(10 * sizeof(Data)));

// 遍历指针范围,逐个构造对象
auto ptr_range = std::ranges::subrange(ppd, ppd + 10);
for (auto p : ptr_range) {
    std::construct_at(p, 45);
}

// 后续销毁和释放内存示例
// for (auto p : ptr_range) {
//     std::destroy_at(p);
// }
// ::operator delete(ppd);

这些方案本质上和你原本的实现逻辑一致,但通过标准库组件提升了代码的可读性和表达性,同时避免了裸指针操作的一些潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 09:09:59