C/C++函数传参时struct/class应该传引用还是传值?

一、什么是PoD数据类型?

具体可以以参考
链接1: 什么是PoD数据类型?
链接2: C++中PoD类型

二、怎么判断一个struct/class是否为PoD类型?

C++11中可以通过类模板进行判断,其新特性is_trivial可以用于判断一个struct/class是否为PoD类型。

定义如下:

template <typename T> struct std::is_trivial;

is_trivial结构成员函数:value的返回值可以指示T是否为PoD类型。
当T包含默认的构造函数,那么T为trivial类型数据,即为PoD类型时,value为true;其他情况下,value为false。(关于trivial与non-trivial与PoD的关系,可参考C++ trivial和non-trivial构造函数及POD类型

三、struct/class作为函数形参时,该如何传值?

根据上文,我们知道如何判断一个struct/class是否为PoD类型?现在我们可以看看struct/class作为形参时,不同的传值类型在效率上的区别。

我们先定义一个结构体

typedef struct NewType{
    int a;
    long b;
    double c;
    long int d;
    short int e;
    long long f;
    long double g;
    uint8_t h;
    //string st;
} tNewType;

很显然,该结构体为PoD类型,我们也可用is_trivial来判断。当我们加入string st (string 为non-PoD类型) 的时候,tNewType就是non-PoD类型,因为它包含自定义的构造函数,为non-trivial类型。

我们测试的思路:分别将tNewType作为函数形参进行值传递和引用传递,来看看其所花费的总时间的差异,以证明不同情况下,传递效率不同。

测试代码如下:

#include <bits/stdc++.h>
#include <sys/time.h>
using namespace std;

typedef struct NewType{
    int a;
    long b;
    double c;
    long int d;
    short int e;
    long long f;
    long double g;
    uint8_t h;
    //string st;
} tNewType;

// 值传递
void Test1(tNewType nt1, tNewType nt2, tNewType nt3, tNewType nt4, tNewType nt5)
{
}

// 引用传递
void Test2(tNewType& nt1, tNewType& nt2, tNewType& nt3, tNewType& nt4, tNewType& nt5)
{
}

// 进行1000000次传参测试
int main()
{
    long int n1 = 0, n2 = 0;
    timeval t1, t2, t3, t4;

    gettimeofday(&t1, nullptr);
    while (n1++ < 1000000) {
        tNewType nt;
        Test1(nt, nt, nt, nt, nt);
    }
    gettimeofday(&t2, nullptr);
    double valms = t2.tv_sec * 1000 + t2.tv_usec / 1000 - (t1.tv_sec * 1000 + t1.tv_usec / 1000);
    printf("val: t2 - t1 = %lf ms.\n", valms);

    gettimeofday(&t3, nullptr);
    while (n2++ < 1000000) {
        tNewType nt;
        Test2(nt, nt, nt, nt, nt);
    }
    gettimeofday(&t4, nullptr);
    double refms = t4.tv_sec * 1000 + t4.tv_usec / 1000 - (t3.tv_sec * 1000 + t3.tv_usec / 1000);
    printf("ref: t4 - t3 = %lf ms.\n", refms);

    if (is_trivial<tNewType>::value) {
        cout << "tNewType is POD. Passed by val is equal to ref." << endl;
    } else {
        cout << "tNewType is non-POD. Passed by ref is better to val." << endl;
    }

    return 0;
}

tNewType为PoD类型结构体时,其测试结果如下:

val: t2 - t1 = 0.000000 ms.
ref: t4 - t3 = 0.000000 ms.
tNewType is POD. Passed by val is equal to ref.

tNewType为non-PoD类型结构体时,其测试结果如下:

val: t2 - t1 = 34.000000 ms.
ref: t4 - t3 = 0.000000 ms.
tNewType is non-POD. Passed by ref is better to val.

可见, 当struct/class为PoD类型的时候,值传递和引用传递效率基本相当,花费时间基本为0。而当struct/class为non-PoD类型时,引用传递效率明显高于值传递。

这是因为当struct/class为non-PoD类型时,值传递会调用struct/class本身或者其non-PoD成员的自定义构造函数或拷贝构造函数,导致额外的开销。

因此,一般struct/class作为函数参数时,我们尽量使用引用传递,最好还是const &。

参考:
[1]: 《Effective C++》
[2]: https://blog.csdn.net/kongkongkkk/article/details/77414410
[3]: https://www.cnblogs.com/tracylee/archive/2012/10/18/2730164.html
[4]: https://www.jianshu.com/p/191f713587cf
[5]: https://blog.csdn.net/a627088424/article/details/48595525
[6]: https://en.cppreference.com/w/cpp/types/is_trivial

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值