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

如何避免用可变参数模板初始化vector时的不必要拷贝?

问题分析与解决方案

为什么会触发不必要的拷贝?

1. create_dummies函数的问题

你用初始化列表{std::forward<Dummies>(value)...}构造vector时,初始化列表的类型是std::initializer_list<Dummy>,而std::initializer_list的元素是**const T&**类型。这意味着即使传入的是右值(比如Dummy(1)),初始化列表也会将其视为const左值,无法调用Dummy的移动构造函数,只能触发拷贝构造。

2. create_elements函数的问题

std::make_any<Comps>(std::forward<Comps>(value))本身是完美转发构造内部对象的,但问题出在vector的初始化列表构造上:初始化列表里的std::any临时对象会被拷贝到vector的元素中,而std::any的拷贝构造会深度拷贝其内部存储的Dummy对象,因此触发了Dummy的拷贝构造。

修复方案

1. 修复create_dummies函数

放弃初始化列表,改用emplace_back直接在vector内存中构造元素,完全避免拷贝:

template<typename... Dummies> 
std::vector<Dummy> create_dummies(Dummies&&... values) {
  std::vector<Dummy> vec;
  vec.reserve(sizeof...(values)); // 预先分配空间,避免扩容带来的额外移动
  (vec.emplace_back(std::forward<Dummies>(values)), ...); // 折叠表达式逐个构造
  return vec;
}

emplace_back会直接在vector的内存区域构造Dummy,传入右值时调用移动构造,传入参数时直接调用对应的构造函数,全程无拷贝。

2. 修复create_elements函数

同样避免初始化列表,用emplace_back结合std::in_place_type直接在std::any内部构造对象,同时避免std::any的拷贝:

template<typename... Comps> 
std::vector<std::any> create_elements(Comps&&... values) {
  std::vector<std::any> vec;
  vec.reserve(sizeof...(values));
  (vec.emplace_back(std::in_place_type_t<std::decay_t<Comps>>{}, std::forward<Comps>(values)), ...);
  return vec;
}

std::in_place_type确保std::any直接在自身内存中构造目标对象,emplace_back则直接在vector内存中构造std::any,全程无拷贝操作。std::decay_t<Comps>用于处理左值引用参数的情况,确保构造的是值类型而非引用类型。

修复效果

修改后的代码运行后,不会输出任何copy dummy的日志,和emplace_back方案的效果完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 17:45:37