c++函数传参的几种推荐方式

比如一个func函数,需要传入一个T类型的很大的x参数用于func内部读取(不修改)。有几种方法:

方法一:值传递

这也是最简单的方法:

cpp 复制代码
void func(T x)
{
    T y = x; // x到y有拷贝
    T y = std::move(x); // x所有权交给y,没有拷贝,但后文不能再用x了
}

调用:

cpp 复制代码
T a;
func(a); // a到x有1次拷贝

由于是值传递,这里a到x需要一次拷贝,x到y如果不用std::move的话又有一次拷贝。

如果不想要a到x的值传递时的拷贝,需要在调用时move:

cpp 复制代码
T a;
func(std::move(a)); // a到x有0次拷贝,1次move构造(move比较轻量)
//这里把a完全交给了func内部,没有拷贝,但后文不能再用a了

结论:

  • 接口最灵活

  • 调用方决定是否拷贝(选择是否std::move(a)),这是 STL 和 Effective Modern C++ 强烈推荐的模式

  • 现代 C++ 非常推荐("pass-by-value + move"惯用法)

方法二:引用传递(只读参数最佳)

类似于c语言的传递指针(不利于对象管理,此处不讨论),但是c++中有一个引用传递的新概念:

cpp 复制代码
void func(const T& x)
{
    T y = x; // x到y有拷贝
}

调用:

cpp 复制代码
T a;
func(a); // x就是a的引用,0次拷贝,0次move构造

这里T&表示传入的就是a的引用,不存在a到x的拷贝过程。const表示传入的x在函数内部不准修改,保证了a不会被func修改掉(func只读a)。

但是const T&不能实现a到y的完全无拷贝传递,一个经典的错误:

cpp 复制代码
void func(const T& x)
{
    // 假的move,实际还是发生了拷贝,因为move的是const T&类型,而不是x的所有权
    T y = std::move(x); 
}

结论:

  • 最佳适用场景

    • 只读

    • 不接管所有权

    • 不需要在函数内部生成新对象

  • 不要指望它"零拷贝生成 y"

方法三:传入右值(所有权传递)

针对const T&不能传入a的所有权从而无拷贝把a给到y的问题,实际应当传入a的右值。

有两种方法:

  1. 方法一种提到的值传递,函数调用一次move把a给到x,函数内部用move再把x给到y,全程0拷贝,2次move (推荐)
cpp 复制代码
void func(T x)
{
    y = std::move(x);  //x到y 0次拷贝,1次move(轻量),后文不能再用x了
}

//调用
T a;
func(std::move(a));  // a到x 0次拷贝,1次move(轻量),后文不能再用a了

这相当于把是否拷贝的选择交给了调用方,调用方可以用func(a)也可以用func(std::move(a)),前者a到x有一次拷贝,后者没有但后文不能再用a了。

  1. 强制只能传入右值,明确接管
cpp 复制代码
void func(T&& x)
{
    T y = std::move(x);  // x到y有0次拷贝,1次move(轻量)
}

//调用
T a;
func(std::move(a)); // a到x 0次拷贝,0次move,因为x不是新对象,已经绑定到a
// func(a); //不允许

这里用T&&表示传入的只能是右值,减少了值传递a到x的move,但也限定了a后文不能再用。

结论:

  • 适合:

    • 明确"我就是要接管你的对象",相比值传递写法可以少1次move。

    • 函数语义就是"消费型接口"

  • 不适合:

    • 公共 API

    • 希望调用方既能传左值又能传右值

所以:T&& 是"语义最强,但最不灵活"的接口。

总结:

  • 只读 → const T&

  • 可能接管 → T(值传递或者std::move())

  • 强制接管 → T&&

  • 别对 const T&std::move

相关推荐
心平气和量大福大4 分钟前
android-实例-蒲公英-更新与安装-5-签名与生成APK
android·java·开发语言
码哥DFS18 分钟前
构造函数、实例对象、对象原型 ----三者关系
开发语言·javascript·原型模式
quantdash_cc1 小时前
告别自建 Requests/BS4 网页爬虫:基于 QuantDash 搭建零维保的高性能量化行情流水线
开发语言·爬虫·python·pandas·量化·quantdash
ydd1001001 小时前
寻找两个正序数组的中位数 Java 题解,二分分割详解
java·开发语言
zh路西法1 小时前
【3D SLAM源码解读系列】(二)Small_gicp——5 个积木搭出最优点云配准
c++·pcl·icp·fastgicp·smallgicp·gicp
半亩码田1 小时前
C#转Python第3.1篇:Python 的 class 没有访问修饰符?面向对象的另一条路
开发语言·python·c#
Wzx1980122 小时前
python沙箱和docker沙箱你选对了吗?
开发语言·python·docker
牧羊人.3332 小时前
Python 办公自动化从入门到入土|09 数据容器之字典
开发语言·python
小僧景贤3 小时前
嵌入式C语言 第二篇:基础语法|嵌入式C与标准C的核心差异
c语言·开发语言·嵌入式c语言
阿pin3 小时前
Android随笔-AIDL
android·开发语言·aidl