C++中从返回值创建tuple时如何避免额外拷贝?
解决方案:利用
std::piecewise_construct原地构造Tuple元素 核心思路是避免创建临时插件对象,直接将构造参数传递给std::tuple,让它在自身内存空间中原地构造每个插件实例,彻底消除拷贝/移动带来的额外析构。
修改后的代码
#include <tuple> #include <iostream> namespace details { template<typename PluginT, typename ContainerT, typename TupleT, size_t... Is> static auto get_plugin_construct_args(ContainerT& container, TupleT&& tuple, std::index_sequence<Is...>) { // 打包插件构造所需的所有参数为tuple return std::forward_as_tuple(container, std::get<Is>(std::forward<TupleT>(tuple))...); } template<typename PluginT, typename ContainerT, typename TupleT> static auto get_plugin_construct_args(ContainerT& container, TupleT&& tuple) { return get_plugin_construct_args<PluginT>( container, std::forward<TupleT>(tuple), std::make_index_sequence<std::tuple_size<std::decay_t<TupleT>>::value>{} ); } } struct simple_plugin { template<typename ContainerT> simple_plugin(ContainerT& container) {} ~simple_plugin() { std::cout << "simple_plugin destructor" << std::endl; } }; struct plugin_with_params { template<typename ContainerT> plugin_with_params(ContainerT& container, int argc, char* argv[]) {} ~plugin_with_params() { std::cout << "plugin_with_params destructor" << std::endl; } }; template<typename... PluginTs> struct plugin_container { std::tuple<PluginTs...> plugins; template<typename... TupleTs> plugin_container(TupleTs&&... tuples) : // 使用piecewise_construct,让tuple为每个元素原地构造 plugins( std::piecewise_construct, details::get_plugin_construct_args<PluginTs>(*this, std::forward<TupleTs>(tuples))... ) {} }; int main(int argc, char* argv[]) { plugin_container<simple_plugin, plugin_with_params> container(std::make_tuple(), std::make_tuple(argc, argv)); return 0; }
关键修改说明
- 替换对象创建为参数打包:将原
construct_plugin返回插件对象的逻辑,改为返回插件构造所需的参数tuple,避免创建临时对象。 - 使用
std::piecewise_construct:这是std::tuple的专用构造标记,告诉tuple要为每个元素分别使用对应的参数tuple进行原地构造,完全跳过临时对象的拷贝/移动步骤。 - 保持模板兼容性:所有插件类的模板构造函数无需修改,也不需要为任何插件手动定义移动/拷贝构造函数,完全符合需求。
修改后每个插件只会被构造一次,程序退出时也只会析构一次,解决了原问题中的两次析构现象。
内容的提问来源于stack exchange,提问作者Alexandre Deus
相关产品推荐
相关产品推荐

