c++中,一个函数返回临时变量,接收者接受这个返回结果作为变量,会造成几次拷贝呢?
#include<iostream>
using namespace std;
class CopyTrack
{
public:
CopyTrack()
{
cout << "[CopyTrack::CopyTrack ]" << endl;
}
CopyTrack(const CopyTrack &c)
{
i = c.i;
cout << "[CopyTrack::copy-constructor]" << endl;
}
~CopyTrack()
{
cout << "[CopyTrack::~CopyTrack]" << endl;
}
int i = 0;
};
CopyTrack GetCopy()
{
CopyTrack c;
c.i = 5;
return c;
}
int main()
{
CopyTrack c = GetCopy();
cout << "c.i=" << c.i << endl;
return 0;
}
按理说,CopyTrack c = GetCopy();这个会导致发生两次拷贝,第1次拷贝发生是GetCopy函数内的临时变量拷贝到结果,第2次是返回结果作为参数生成c。但实际没有发生任何拷贝
root@ubuntu:~/share/test/cpp# g++ copy.cpp
root@ubuntu:~/share/test/cpp# ./a.out
[CopyTrack::CopyTrack ]
c.i=5
[CopyTrack::~CopyTrack]
root@ubuntu:~/share/test/cpp#
这和编译器有关,修改编译器参数,把相关优化去掉,-fno-elide-constructors,便发生了两次拷贝
root@ubuntu:~/share/test/cpp# g++ -fno-elide-constructors copy.cpp
root@ubuntu:~/share/test/cpp# ./a.out
[CopyTrack::CopyTrack ]
[CopyTrack::copy-constructor]
[CopyTrack::~CopyTrack]
[CopyTrack::copy-constructor]
[CopyTrack::~CopyTrack]
c.i=5
[CopyTrack::~CopyTrack]
root@ubuntu:~/share/test/cpp#
如何变成一次拷贝呢?
方法一,不用变量名
int main()
{
//CopyTrack c = GetCopy();
//cout << "c.i=" << c.i << endl;
cout << "c.i=" << GetCopy().i << endl;
return 0;
}
root@ubuntu:~/share/test/cpp# g++ -fno-elide-constructors copy.cpp
root@ubuntu:~/share/test/cpp# ./a.out
c.i=[CopyTrack::CopyTrack ]
[CopyTrack::copy-constructor]
[CopyTrack::~CopyTrack]
5
[CopyTrack::~CopyTrack]
root@ubuntu:~/share/test/cpp#
方法2,用右值引用
int main()
{
CopyTrack &&c = GetCopy();
cout << "c.i=" << c.i << endl;
//cout << "c.i=" << GetCopy().i << endl;
return 0;
}
root@ubuntu:~/share/test/cpp# g++ -fno-elide-constructors copy.cpp
root@ubuntu:~/share/test/cpp# ./a.out
[CopyTrack::CopyTrack ]
[CopyTrack::copy-constructor]
[CopyTrack::~CopyTrack]
c.i=5
[CopyTrack::~CopyTrack]
root@ubuntu:~/share/test/cpp#
那怎样让其一次拷贝也没有呢?
右值引用的问题
右值引用一个左值不可以,但作为函数参数,右值引用左值却可以。这是因为在普通函数中T &&为右值引用,但在模板参数中T&& 可能是左值引用,也可能是右值引用。模板参数中T &为强制左值引用。
template<typename T>
void Pkg(T &&t)
{
t.i = 3;
}
int main()
{
CopyTrack c = GetCopy();
CopyTrack && c1 = c; //error
Pkg(c); //okay
cout << "c.i=" << c.i << endl;
//cout << "c.i=" << GetCopy().i << endl;
return 0;
}