網(wǎng)站首頁 編程語言 正文
一、初探臨時(shí)對(duì)象
1.問題
下面的程序輸出什么?為什么?
下面編寫程序進(jìn)行實(shí)驗(yàn):
#include <stdio.h>
class Test {
int mi;
public:
Test(int i) {
mi = i;
}
Test() {
Test(0);
}
void print() {
printf("mi = %d\n", mi);
}
};
int main()
{
Test t;
t.print();
return 0;
}
輸出結(jié)果如下:
程序意圖:
- 在 Test() 中以 0 作為參數(shù)調(diào)用 Test(int i)
- 將成員變量 mi 的初始值設(shè)置為 0
運(yùn)行結(jié)果:
- 成員變量 mi 的值為隨機(jī)值
2.思考
構(gòu)造函數(shù)是一個(gè)特殊的函數(shù)
- 是否可以直接調(diào)用?
- 是否可以在構(gòu)造函數(shù)中調(diào)用構(gòu)造函數(shù)?
- 直接調(diào)用構(gòu)造函數(shù)的行為是什么?
3.答案
- 直接調(diào)用構(gòu)造函數(shù)將產(chǎn)生一個(gè)臨時(shí)對(duì)象
- 臨時(shí)對(duì)象的生命周期只有一條語句的時(shí)間(過了這條 C++ 語句,臨時(shí)對(duì)象將被析構(gòu)而不復(fù)存在)
- 臨時(shí)對(duì)象的作用域只在一條語句中
- 臨時(shí)對(duì)象是 C++ 中值得警惕的灰色地帶
可以將上面代碼寫成這樣,避免臨時(shí)對(duì)象:
#include <stdio.h>
class Test {
int mi;
void init(int i)
{
mi = i;
}
public:
Test(int i) {
init(i);
}
Test() {
init(0);
}
void print() {
printf("mi = %d\n", mi);
}
};
int main()
{
Test t;
t.print();
return 0;
}
輸出結(jié)果如下:
再來看一個(gè)程序,深刻體會(huì)一下臨時(shí)對(duì)象:
#include <stdio.h>
class Test {
int mi;
void init(int i)
{
mi = i;
}
public:
Test(int i) {
printf("Test(int i)\n");
init(i);
}
Test() {
printf("Test()\n");
init(0);
}
void print() {
printf("mi = %d\n", mi);
}
~Test()
{
printf("~Test()\n");
}
};
int main()
{
printf("main begin\n");
Test();
Test(10);
printf("main end\n");
return 0;
}
輸出結(jié)果如下:
這個(gè)程序很好的說明了臨時(shí)對(duì)象的生命周期只有一條語句的時(shí)間(過了這條 C++ 語句,臨時(shí)對(duì)象將被析構(gòu)而不復(fù)存在)
二、編譯器的行為
現(xiàn)代 C++ 編譯器在不影響最終執(zhí)行結(jié)果的前提下,會(huì)盡力減少臨時(shí)對(duì)象的產(chǎn)生!!!
下面來看一個(gè)例子:
#include <stdio.h>
class Test
{
int mi;
public:
Test(int i)
{
printf("Test(int i) : %d\n", i);
mi = i;
}
Test(const Test& t)
{
printf("Test(const Test& t) : %d\n", t.mi);
mi = t.mi;
}
Test()
{
printf("Test()\n");
mi = 0;
}
int print()
{
printf("mi = %d\n", mi);
}
~Test()
{
printf("~Test()\n");
}
};
Test func()
{
return Test(20);
}
int main()
{
//Test t(10); 等價(jià)于 Test t = Test(10);
Test t = Test(10); // ==> Test t = 10;
Test tt = func(); // ==> Test tt = Test(20); ==> Test tt = 20;
t.print();
tt.print();
return 0;
}
輸出結(jié)果如下:
注意兩點(diǎn):
- 通過輸出結(jié)果可以看到【編譯器并沒有按照生成臨時(shí)對(duì)象,再用臨時(shí)對(duì)象初始化 t 對(duì)象(其中涉及調(diào)用拷貝構(gòu)造函數(shù))】的步驟,因?yàn)楝F(xiàn)代的編譯器都會(huì)盡力避免臨時(shí)對(duì)象的產(chǎn)生。
- Test t = Test(10); 等價(jià)于 Test t = 10; 寫成Test t = 10; 可以杜絕臨時(shí)對(duì)象的產(chǎn)生。因?yàn)榕R時(shí)對(duì)象的產(chǎn)生會(huì)帶來性能上的問題,Test t = Test(10); 相當(dāng)于調(diào)用了兩次構(gòu)造函數(shù), 而 Test t = 10; 少調(diào)用一次函數(shù),性能得到提升。
三、小結(jié)
- 直接調(diào)用構(gòu)造函數(shù)將產(chǎn)生一個(gè)臨時(shí)對(duì)象
- 臨時(shí)對(duì)象是性能的瓶頸,也是 bug 的來源之一
- 現(xiàn)代 C++ 編譯器會(huì)盡力避開臨時(shí)對(duì)象
- 實(shí)際工程開發(fā)中需要人為的避開臨時(shí)對(duì)象
原文鏈接:https://blog.csdn.net/weixin_43129713/article/details/124188079
相關(guān)推薦
- 2022-09-14 React路由組件傳參的三種方式(params、search、state)_React
- 2022-03-17 Android跳轉(zhuǎn)三方應(yīng)用實(shí)例代碼_Android
- 2023-02-06 詳解Golang中select的使用與源碼分析_Golang
- 2022-09-21 詳解C語言中typedef和#define的用法與區(qū)別_C 語言
- 2022-10-22 python常用數(shù)據(jù)結(jié)構(gòu)字典梳理_python
- 2024-02-16 springboot開啟mybatis二級(jí)緩存
- 2022-04-25 淺談Golang?Slice切片如何擴(kuò)容的實(shí)現(xiàn)_Golang
- 2023-07-16 uniapp 中 uni.navigateTo跳轉(zhuǎn)其他頁面 并且?guī)?shù)
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支