C++ C++;速度差为;“按价值”;vs";引用;

C++ C++;速度差为;“按价值”;vs";引用;,c++,performance,pass-by-reference,pass-by-value,C++,Performance,Pass By Reference,Pass By Value,我想测试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); s

我想测试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;}
类MyAddress{
字符*名称;
长整数;
查*街;
查尔镇;
半焦态[2];
长拉链;
std::向量v_int;
公众:
我的地址(int i){
v_int.resize(1000000);
std::fill(v_int.begin(),v_int.end(),i);
}
我的地址和分配1(我的地址常量和x)
{ 
MyAddress tmp(x);//tmp的复制构造是一项艰巨的工作
std::swap(*this,tmp);//用我们的资源交换tmp的资源
return*this;//我们的(旧)资源被tmp破坏
}
MyAddress&assign2(MyAddress x)//x是源的副本
{//已经做了艰苦的工作
交换(*this,x);//用我们的资源交换x
return*this;//我们的(旧)资源被x破坏
}
void f1(MyAddress v){int i=v.v_int[3];}
void f2(MyAddress const&ref){int i=ref.v_int[3];}
};
MyAddress获取_名称(MyAddress&ref){return ref;}
主要内容:

int-tmain(int-argc,_-TCHAR*argv[]
{
浮动时间_elapsed1=0;
浮动时间_elapsed2=0;

对于(int i=0;i输出的措辞有一些混乱:您没有在代码中的任何地方使用
assign1
assign2
,但是您在输出中提到了它们


不管怎么说,在看到您实际执行的操作之后,我只能说,
f1
按值获取参数,这意味着它调用了复制构造函数,而复制构造函数又复制了太大的成员向量。复制向量需要这么多的时间,当您调用
f2
时可以节省时间,因为它通过引用获取参数,因此,在这种情况下,没有对向量进行复制。

除了已经说过的关于昂贵的复制构造函数的内容之外,我想提到的是,你只是在扔掉
f1
f2
中的计算结果。这意味着在理论上(假设向量是以一种可能的方式实现的)编译器可以决定在只读取值的情况下删除整个方法调用,很明显删除它们不会产生副作用。这意味着,您可能最终只测量启动和停止计时器本身所需的时间


无论如何,除了少数情况外,您应该期望通过引用调用的速度更快,至少如果您正在传递一个大对象。

为什么要使用
std::vector
,而不是
std::string
?现在您没有遵循3/5/6/规则,不管您想调用它什么。无论如何,通过值传递可以调用昂贵的副本构造函数。这并不奇怪。复制4MB向量需要一些时间。你没有在代码中的任何地方使用
assign1
assign2
,但你在输出中提到了它们?我昨天确实做了类似的测试。我花了大约6分钟的时间复制1GB内存100次(按值计算),但按u计算78mssing move语义。by值真的可以加起来。@zch说了什么。但你可能仍然需要一台新机器-我得到的最慢运行时间(使用非优化编译)约为6秒。不,总之在f2()中int是从向量中读取的,对吗?所以我有比较-这就是我想要的see@cf16是的,在这两种情况下,你都在读取向量,但是你在丢弃结果,我们能同意吗?你返回
void
,变量
i
从未存储或传递到任何地方。这意味着如果编译器是clever,它将决定完全跳过计算,因为没有人会听到结果。这就是直线代码、死存储消除和死代码消除等技术的全部内容(所有这些都与本例相关,请查看它们).但如果编译器决定跳过,这两个函数不是都是这样吗?都返回void,对吗?你说的都是这两个函数的问题,但时间不同differ@cf16不同之处在于,如果编译器可以删除整个函数调用,那么可能会受到更多的影响。类的创建可能会产生副作用(例如打印)例如,对stdout来说,“我是构造函数”,处理这一点要困难得多,因此导致这一点的代码很可能会保留下来。你是对的,你所做的更改使优化的可能性降低。尽管我已经说过了很多,但是我应该指出,
操作符[]的向量实现
本身可能是一个太复杂而无法完全删除的方法。但这很难确定。@cf16另外,不要把我的回答看作是对这种特殊情况下执行时间差异的解释。新对象的分配和初始化肯定是原因,我个人使用const引用我只是说,为了进行公平的比较,你应该确保不同的方法实际上做了完全相同的事情。你通常可以在编译器中控制优化级别,但在非优化代码中比较效率也可能不是你想要做的,因为你只会发布优化的代码E
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;
}