C++templates第七章按值传递还是按引用传递?

从一开始,C++就提供了按值传递(call-by-value)和按引用传递(call-by-reference)两种参 数传递方式,但是具体该怎么选择,有时并不容易确定:通常对复杂类型用按引用传递的成本更低,但是也更复杂。C++11 又引入了移动语义(movesemantics),也就是说又多了一 种按引用传递的方式。

按值传递

当按值传递时,原则上所有参数都会被拷贝,因此每一个参数都会是被传递实参的一份拷贝,对于class对象,会通过class拷贝构造函数去初始化

调用拷贝构造函数成本会很高,我们可以通过移动语义去优化,如下所示:

1
2
3
4
5
template<typename T> 
void printV (T arg)
{
// ...
}

参数arg会变成是残的一次拷贝,但是不是所有情况都回调用拷贝构造函数:

1
2
3
4
5
6
std::string returnString(); 
std::string s = "hi";
printV(s); //copy constructor
printV(std::string("hi")); //copying usually optimized away (if not, move constructor)
printV(returnString());// copying usually optimized away (ifnot, move constructor)
printV(std::move(s)); // move constructor

在第一次调用中,被传递的参数是左值(lvalue),因此拷贝构造函数会被调用。但是在第 二和第三次调用中,被传递的参数是纯右值,此时编译器会优化参数传递,使得拷贝构造函数不会被调用

按值传递会导致类型退化

1
2
3
4
5
6
7
8
9
10
template<typename T> 
void printV (T arg)
{

}
std::string const c = "hi";
printV(c); // c decays so that arg has type std::string
printV("hi"); //decays to pointer so that arg has type char const*
int arr[4];
printV(arr); // decays to pointer so that arg has type int *

按引用传递

按const引用传递

为了避免(不必要的)拷贝,在传递非临时对象作为参数时,可以使用 const 引用传递。比如:

1
2
3
4
5
template<typename T> 
void printR (T const& arg)
{
//..
}

引用传递不会做类型退化

按引用传递参数时,其类型不会退化(decay)。也就是说不会把裸数组转换为指针,也不会移除 const 和 volatile 等限制符。而且由于调用参数被声明为 Tconst&,被推断出来的模 板参数 T 的类型将不包含 const