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

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;
}

关键修改说明

  1. 替换对象创建为参数打包:将原construct_plugin返回插件对象的逻辑,改为返回插件构造所需的参数tuple,避免创建临时对象。
  2. 使用std::piecewise_construct:这是std::tuple的专用构造标记,告诉tuple要为每个元素分别使用对应的参数tuple进行原地构造,完全跳过临时对象的拷贝/移动步骤。
  3. 保持模板兼容性:所有插件类的模板构造函数无需修改,也不需要为任何插件手动定义移动/拷贝构造函数,完全符合需求。

修改后每个插件只会被构造一次,程序退出时也只会析构一次,解决了原问题中的两次析构现象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:09:59