【问题标题】:C++ speed differences of "by value" vs "by reference" [closed]“按值”与“按引用”的 C++ 速度差异 [关闭]
【发布时间】:2012-05-27 08:58:00
【问题描述】:

我想测试C++中值传递和引用传递的速度:

class MyAddress{
    char *name;
    long int number;
    char *street;
    char *town;
    char state[2];
    long zip;
    std::vector<int> v_int;
public:
    MyAddress(int i){
        v_int.resize(1000000);
        std::fill(v_int.begin(),v_int.end(),i);
    }
    MyAddress& assign1(MyAddress const& x)
    { 
        MyAddress tmp(x);       // copy construction of tmp does the hard work
        std::swap(*this, tmp);  // trade our resources for tmp's
        return *this;           // our (old) resources get destroyed with tmp 
    }
    MyAddress& assign2(MyAddress x)//x is a copy of the source 
    {                              //hard work already done

        std::swap(*this, x);  // trade our resources for x's
        return *this;         // our (old) resources get destroyed with x 
    }
    void f1(MyAddress v){int i=v.v_int[3];}
    void f2(MyAddress const &ref){int i=ref.v_int[3];}

};

MyAddress get_names(MyAddress& ref){return ref;}

主要:

int _tmain(int argc, _TCHAR* argv[])
{
    float time_elapsed1=0;
    float time_elapsed2=0;

    for(int i=0;i<100;i++){
        {
            MyAddress a1(1);
            MyAddress a2(2);
            MyAddress a3(3);
            clock_t tstart=std::clock();
            a1.f1(a2);
            a1.f1(a3);
            clock_t tend=std::clock();
            time_elapsed1+=((float)tend-(float)tstart);
        }
        {
            MyAddress a1(1);
            MyAddress a2(2);
            MyAddress a3(3);
            clock_t tstart=std::clock();
            a1.f2(a2);
            a1.f2(a3);
            clock_t tend=std::clock();
            time_elapsed2+=((float)tend-(float)tstart);
        }
    }
    std::cout<<std::fixed<<"\nassign1 time elapsed : "
         <<time_elapsed1/CLOCKS_PER_SEC;
    std::cout<<std::fixed<<"\nassign2 time elapsed : "
         <<time_elapsed2/CLOCKS_PER_SEC;
    system("pause");
    return 0;
}

时差结果令人震惊:

assign1 已用时间:81.044998

assign2 已用时间:0.002000

这对吗?

“按价值”的速度怎么会比“按参考”高得多?

【问题讨论】:

  • 你为什么用std::vector,而不是std::string?现在你没有遵循 3/5/6/无论你想怎么称呼它的规则。无论如何,按值传递会调用昂贵的复制构造函数。
  • 并不奇怪。复制 4MB 向量需要一些时间。
  • 您没有在代码中的任何地方使用assign1assign2,但您在输出中提到了它们?
  • 我昨天实际上做了一些类似的测试。我花了大约 6 分钟将 1GB 的内存按值复制 100 次,但使用移动语义需要 78 毫秒。按值真的可以加起来。
  • @zch 说了什么。但是您仍然可能需要一台新机器 - 我得到的最慢运行(使用非优化编译)大约是 6 秒。

标签: c++ performance pass-by-reference pass-by-value


【解决方案1】:

您的输出措辞有些混乱:您没有在代码中的任何地方使用assign1assign2,但您在输出中提到了它们。

无论如何,在看到你实际在做什么之后,我只能说f1 通过 value 接受参数,这意味着它调用了复制构造函数,然后复制了成员向量这太大了。向量的这种复制花费了很多时间,当您调用 f2 时您可以节省这些时间,因为它通过引用获取参数,因此在这种情况下不会复制向量。

【讨论】:

    【解决方案2】:

    除了已经说过的昂贵的复制构造函数之外,我想提一下,您只是在丢弃f1f2 中的计算结果。这意味着理论上(假设向量的实现方式使得这成为可能)编译器可以决定在仅读取值时删除整个方法调用,并且很明显删除它们不会导致副作用。这意味着,您最终可能只测量启动和停止计时器本身所需的时间。

    无论如何,您应该期望引用调用在所有情况下都更快,但在少数情况下,至少在您传递一个大对象时是这样。

    【讨论】:

    • 不,总而言之,在 f2() 中,int 是从向量中读取的,对吧?所以我有比较 - 这是我想看到的
    • @cf16 是的,你在两种情况下都从向量中读取,但是你丢弃了结果,我们可以同意吗?您正在返回void,变量i 永远不会在任何地方存储或传递。这意味着如果编译器很聪明,它会决定完全跳过计算,因为没有人会听到结果。这就是compiler optimization 技术,如直线代码死存储消除死代码消除的全部内容(所有这些都是相关的在这种情况下,请检查它们)。
    • 但是如果编译器决定跳过,这两个函数不都是这样吗?两者都返回无效吗?你说的这两个都属于他们,但时间不同
    • @cf16 不同之处在于,如果编译器可以删除整个函数调用,那么可能会受到更多影响。一个类的创建可能会产生副作用(例如将“我是构造函数”打印到标准输出),并且处理它要困难得多,因此导致这种情况的代码可能会保留下来。您是对的,您所做的更改使优化的可能性降低。尽管如此,我还是应该指出,operator[] 的向量实现本身可能是一种过于复杂而无法完全删除的方法。但很难确定。
    • @cf16 另外,不要将我的回答视为在这种特殊情况下执行时间差异的解释。新对象的分配和初始化肯定是这里的原因,我个人一直使用 const 引用。我只是说,为了进行公平的比较,您应该确保不同的方法实际上在做完全相同的事情。您通常可以在编译器中控制优化级别,但在未优化代码中比较效率可能也不是您想要做的,因为您只会发布优化代码...
    猜你喜欢
    • 1970-01-01
    • 2018-07-29
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    • 2011-05-08
    • 2012-03-03
    相关资源
    最近更新 更多