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

std::make_pair()为何使用右值引用作为形参类型?

关于make_pair使用T&&形参的核心说明

首先纠正一个常见认知误区:这个函数签名里的t1&&、t2&&不是普通的右值引用,而是C++11引入的转发引用(也叫万能引用),它天生就同时支持左值、右值传入,根本不存在“无法接收左值”的问题。


为什么它能同时支持左值、右值传入?

这是模板参数推导+引用折叠规则共同作用的结果:

  • 当传入左值时,模板会把t1/t2推导为对应类型的左值引用。比如传入int类型左值,t1会被推导为int&,经过引用折叠规则处理后,int& &&会坍缩为int&(左值引用形参),可以正常绑定左值。
  • 当传入右值时,模板会把t1/t2推导为原始值类型。比如传入int类型右值,t1会被推导为int,形参类型就是int&&(右值引用形参),可以正常绑定右值。

你可以直接写代码验证这个特性:

int a = 10;
auto p = std::make_pair(a, 20); // 传入左值a,完全可以正常编译运行

这里使用转发引用形参的实际作用

核心目的是配合std::forward实现完美转发,在不丢失参数值类别的前提下把参数传给pair的构造函数,把运行性能拉到最优,对比其他写法的劣势就能直观看出优势:

  • 对比C++11之前的const T&形参版本
    老版本make_pair的签名是pair<T1,T2> make_pair(const T1& x, const T2& y),它只能通过const左值引用绑定对象,构造pair内部元素时只能走拷贝构造,哪怕传入的是可以直接转移资源的临时对象,也没法触发移动语义,会产生无意义的拷贝开销。
  • 对比值传递形参版本
    如果写成make_pair(T1 x, T2 y),不管传左值还是右值,形参本身都要先完成一次拷贝/移动构造,多了一层不必要的开销,尤其是传入大尺寸对象左值时,拷贝成本非常高。
  • 转发引用版本的实际收益
    它可以完整保留传入参数的值类别:传入左值时,最终调用拷贝构造初始化pair内的元素,符合左值拷贝的语义;传入右值(临时对象、std::move转换后的对象)时,最终调用移动构造初始化pair内的元素,直接转移对象内部的堆资源,完全没有额外拷贝开销。

举个直观的性能对比例子:

std::string large_str(100000, 'a'); // 一个占用10w字节堆内存的大字符串
// 传左值large_str:走拷贝构造,pair内的字符串复制一份原内容,原字符串保留不变
auto p1 = std::make_pair(large_str, 1);
// 传std::move(large_str):走移动构造,pair内的字符串直接拿走原字符串的堆内存指针,原字符串变为空,无拷贝开销
auto p2 = std::make_pair(std::move(large_str), 2);
// 传临时字符串对象:直接移动构造,无拷贝开销
auto p3 = std::make_pair(std::string(100000, 'b'), 3);

一个容易踩的判断误区

不要看到&&就判定为右值引用:

  • 如果&&前面是确定的非推导类型,比如void func(int&& x)、void func(std::string&& s),这才是普通右值引用,只能绑定右值,不能接收左值。
  • 如果&&前面是需要靠传入参数推导的模板类型,比如make_pair里的t1&&,这就是转发引用,可以绑定左值、右值、不同const属性的所有对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 18:36:51