Cpp/C++

C++ 函数的一些重点

2018-10-18  本文已影响9人  Jimmy_L_Wang

函数的引用参数使用

通过引用传递参数

一般函数,如:

int addition (int a, int b)
{
  int r;
  r=a+b;
  return r;
}

...

int x=5, y=3, z;
z = addition ( x, y );

其参数总是按值传递。这意味着,在调用函数时,传递给函数的是调用时这些参数的值,这些值被复制到函数表示的变量中。

在这种情况下,函数不是传递5和3,而是拷贝了x和y的副本。这些值(5和3)用于初始化函数定义中的参数,但函数中这些变量的任何修改都不会影响其外部的变量x和y的值,因为x和y是它们本身没有传递给调用函数,而只是那一刻它们的值的副本。

void duplicate (int& a, int& b, int& c)
{
  a*=2;
  b*=2;
  c*=2;
}

当通过引用传递变量时,传递的内容不再是副本,而是变量本身(由函数参数标识的变量)以某种方式与传递给函数的参数相关联,并且对其中对应的局部变量进行任何修改该函数反映在调用中作为参数传递的变量中

基于效率考量来使用引用参数

使用带值的参数调用函数会导致值的副本生成。对于诸如此类的基本类型,这是相对小的开销,但是如果参数是大型复合类型,则可能导致某些内存开销巨大。如:

string concatenate (string a, string b)
{
  return a+b;
}

此函数将两个字符串作为参数(按值),并返回连接它们的结果。通过按值传递参数,函数强制a并b成为调用时传递给函数的参数的副本。如果这些是长字符串,则可能意味着仅为函数调用复制大量数据。

但是,如果两个参数都被引用,则可以完全避免此副本的生成:

string concatenate (string& a, string& b)
{
  return a+b;
}

引用参数不需要副本。该函数直接对作为参数传递的字符串(别名)进行操作,并且最多可能意味着将某些指针传递给该函数。在这方面,concatenate获取引用的版本比获取值的版本更有效,因为它不需要复制昂贵的复制字符串。

另一方面,具有引用参数的函数通常被视为会修改传递的参数。

解决方案是使函数保证其参数参数不会被此函数修改。这可以通过将参数限定为常量来完成:

string concatenate (const string& a, const string& b)
{
  return a+b;
}

过限定它们const,该函数被禁止修改既不ab,也可以实际访问它们的值作为引用(参数的别名),而不必生成字符串的实际副本。

内联函数

调用函数通常会导致一定的开销(堆栈参数,跳转等等),因此对于非常短的函数,简单地插入它的函数的代码比调用函数可能更有效。

在使用说明inline之前的函数声明通知编译器内联扩展优先于特定函数的一般函数调用机制。这并不会改变函数的所有行为,而只是用于建议编译器函数体生成的代码应该在调用函数的每个点插入,而不是通过常规函数调用来调用。

例如,内联声明为:

inline string concatenate (const string& a, const string& b)
{
  return a+b;
}

Lambda 函数与表达式

C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。

Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

Lambda 表达式本质上与函数声明非常类似。

[capture](parameters)->return-type{body}
[](int x, int y){ return x < y ; }

[](int x, int y) -> int { int z = x + y; return z + x; }

在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:

[]      // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。

另外有一点需要注意。对于[=][&]的形式,lambda 表达式可以直接使用 this 指针。但是,对于[ ]的形式,如果要使用 this 指针,必须显式传入:

[this]() { this->someFunc(); }();

这通知编译器在concatenate调用时,程序更喜欢内联扩展功能,而不是执行常规调用。inline仅在函数声明中指定,而不是在调用时指定。

请注意,大多数编译器已经优化了代码,以便在他们看到提高效率的机会时生成内联函数,即使没有使用inline符明确标记。因此,此说明符仅指示编译器内联是此函数的首选,尽管编译器可以自由地不内联它,否则优化。在C++中,优化是委托给编译器的任务,只要生成的行为是代码指定的行为,就可以自由生成任何代码。

上一篇 下一篇

猜你喜欢

热点阅读