如何构造含不可移动不可复制对象的可指定数量std::array?
问题描述
需要创建一个包含27个不可移动、不可复制对象的数组,后续直接使用对象的引用。
对象定义
class Object { public: explicit Object(std::size_t initial = 1) : value_(initial) {} Object(const Object &) = delete; Object(Object &&) = delete; Object &operator=(const Object &) = delete; Object &operator=(Object &&) = delete; private: std::size_t value_; };
尝试实现及报错
尝试用std::to_array和std::experimental::make_array构造数组,代码如下:
template <size_t... Is> auto create_semaphores_array_details(size_t concurrency_per_service, std::index_sequence<Is...> /*unused*/) { return std::to_array( {(Is, Object(concurrency_per_service))...}); }; template <size_t amount_of_services> auto create_semaphores_array(size_t concurrency_per_service) { return create_semaphores_array_details( concurrency_per_service, std::make_index_sequence<amount_of_services>()); }; constexpr size_t amount_of_services = 27; std::array<Object, amount_of_services> semaphores_per_services = create_semaphores_array<amount_of_services>( 5);
- 使用
std::to_array时,报错:is_move_constructible failed - 使用
std::experimental::make_array时,报错:use of deleted Object(Object &&)
核心问题:如何构造这类数组,同时能灵活修改数组中的对象数量?
解决方案
因为Object既不能复制也不能移动,必须直接在数组的内存空间中原位构造每个对象,不能先创建临时对象再移动/复制。以下是几种简洁可行的方法:
方法1:C++20原位构造法(推荐)
利用std::construct_at直接在std::array的每个元素内存位置上构造对象:
#include <array> #include <utility> #include <memory> template <size_t amount_of_services> std::array<Object, amount_of_services> create_semaphores_array(size_t concurrency_per_service) { std::array<Object, amount_of_services> arr; // 通过索引序列遍历每个位置,原位构造 auto construct_elements = [&]<size_t... Is>(std::index_sequence<Is...>) { (std::construct_at(&arr[Is], concurrency_per_service), ...); }; construct_elements(std::make_index_sequence<amount_of_services>()); return arr; } // 使用示例 constexpr size_t amount_of_services = 27; std::array<Object, amount_of_services> semaphores_per_services = create_semaphores_array<amount_of_services>(5);
这种方式完全规避了移动/复制操作,直接在数组的内存空间里创建对象,安全高效。
方法2:C++17聚合初始化法
利用折叠表达式和聚合初始化,直接在数组初始化时构造每个元素:
#include <array> #include <utility> template <size_t... Is> auto create_array_impl(size_t val, std::index_sequence<Is...>) { return std::array<Object, sizeof...(Is)>{ // 借助索引序列展开,每个元素直接原位构造 (static_cast<void>(Is), Object(val))... }; } template <size_t N> auto create_semaphores_array(size_t concurrency_per_service) { return create_array_impl(concurrency_per_service, std::make_index_sequence<N>()); } // 使用示例 constexpr size_t amount_of_services = 27; std::array<Object, amount_of_services> semaphores_per_services = create_semaphores_array<amount_of_services>(5);
C++17的聚合初始化允许直接在数组元素位置构造不可移动/复制的对象,只要初始化表达式是直接构造而非临时对象转移。
灵活调整数组大小
上述方法都通过模板参数指定数组长度,修改时只需调整模板参数值即可。比如要创建30个对象,只需把constexpr size_t amount_of_services = 30;,再调用create_semaphores_array<30>(5)就行。
内容的提问来源于stack exchange,提问作者arniiiii_ua
相关产品推荐
相关产品推荐

