【C++】临时对象

一、临时量与临时对象

临时量:

  1. 内置类型生成的临时量是常量(临时量,寄存器带出来)。

  2. 自定义类型生成的临时量是变量 ,在内存中。

临时对象:

临时对象是系统临时分配的对象,在没主动声明所需对象而又使用其功能时产生的

注意: 临时对象的生存周期只在本条语句。

二、哪些情况产生临时量

2.1 调用构造函数生成的对象

1
2
3
4
5
6
7
8
9
10
11
12
class A
{
public:
A(int x);
// explicit A(int x);
};

void doSomething(A aObject);
A aObj; // 显示对象
doSomething(aObj);
doSomething(28); // 产生了隐式临时对象,编译器调用A(28)将28隐式构造成A类对象
doSomething(A(28)); // 产生了显示临时对象

如果不想让编译器隐式调用构造函数,只需用explicit修饰只需要传一个参数的构造函数。

三、临时变量的引用

3.1 禁止非常量引用

《Effective C++ 第三版》第二十一条规劝,返回对象时,别妄想返回其引用。根源在于:临时对象的生命周期只在本语句。函数返回时,临时变量会被销毁,将引用一个被销毁的对象,这种行为未定义。

在VS2013下测试,函数参数为非常量引用指向临时对象:

1
2
3
4
5
6
7
#include <string>

void f1(string &str) {
printf("%s\n", str.c_str());
}

f1("hello jiang"); // 错误,"hello jiang"被转成string临时对象,无法非常量引用临时对象

上面代码无法编译通过,说明编译器明确指出了这种写法是错误的。错误前置出现在编译期间,较好防范。

在VS2013下测试,函数返回值为非常量引用指向临时对象:

1
2
3
4
5
6
7
8
9
10
11
#include <string>

int & f2(void) {
int t = 3;
return t;
}

int main() {
int &a = f2(); // 编译通过
return 0;
}

虽然上面代码编译通过了,但是存在潜在风险,程序行为未定义。这种情况尤为注意,因为错误将在运行期出现。其实我好奇的是C++标准为什么不延长这种情况下,临时变量的生命周期。

3.2 常量引用

临时变量是由编译器生成的,C++语言规范没规定编译器生成临时变量的规则,程序员无法得知由编译器生成的临时变量的名字,程序员无法访问那个临时变量。这意味着,以引用的方式传递一个临时变量做为函数参数,如果函数内部对此临时变量做了修改,那么函数返回后,程序员无法获得函数对临时变量的修改。函数对临时变量所做出的所有更改,都将丢失。C++标准为防止给常量或临时变量(只有瞬间的生命周期)赋值(易产生bug),只许使用const引用之。

在VS2013下测试,函数参数为常量引用指向临时对象:

1
2
3
4
5
6
7
8
9
10
11
#include <string>

void f3(const string &str) {
printf("%s\n", str.c_str());
}


int main() {
f3("hello jiang"); // 允许,"hello jiang"被隐式转成string临时对象,使用常量引用之。
return 0;
}

在VS2013下测试,函数返回值为常量引用指向临时对象:

1
2
3
4
5
6
7
8
9
10
11
#include <string>

const int & f4(void) {
int t = 32;
return t;
}

int main() {
const int &a = f4(); // 允许
return 0;
}

四、优化包含临时对象的程序

  • 函数调用传对象时,如果可以,尽量按对象引用来传递,避免构造临时对象
  • 函数调用时,按对象引用来传递,如果不需要修改对象,使用const引用,以避免无意修改对象。
  • 返回对象时,别妄想返回其引用
  • 调用返回对象的函数时,应该以初始化的方式调用,不要以赋值的方式调用,否则会多调用一次构造函数。
------ 本文结束------
赞赏此文?求鼓励,求支持!
  • 本文标题: 【C++】临时对象
  • 本文作者: Jiang.G.F
  • 创建于: 2020年02月02日 - 00时02分
  • 更新于: 2020年03月03日 - 11时03分
  • 本文链接: https://gfjiangly.github.io/C++/temporary_object.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
0%