面試官問我:“為什么不能完全用對象替代指針?”我笑了:看看Google和Linux內核代碼就知道了!

本篇摘要

  • 本篇將以最通俗易懂的語言,形象的講述為什么很多情境下,我們優先考慮的使用指針而不是對象本身,本篇將給出你答案!

在這里插入圖片描述

一.從一個生活例子說起,形象秒懂

想象一下,你去圖書館借書,下面你有兩種選擇:

  • 把整本書復印一份帶回家,但是,書很厚,復印要時間,占地方,還容易丟。

  • 只拿一張“借書卡”,上面寫著書名和位置,而且, 輕便、快速、隨時可以查。

此時我們大多數人就會直接選擇第二種方案了,主打一個通透!

在編程中:

“復印書” = 直接定義對象

Book book;  // 在函數里定義,函數結束就沒了

“借書卡” = 指針

Book* ptr = new Book();  // 拿個“卡”,書在別處(堆上)

指針就像“借書卡”——它不存對象本身,只存對象的“地址”。

二·那為啥不直接“看書”,非要用“借書卡”呢(也就是為什么選擇用指針而不是對象呢)?

可以這么認為因為有時候,“直接看書”根本做不到!

下面我們經常下面幾個方面展開敘述:

原因簡要說明
動態生命周期管理對象可以在運行時創建/銷毀,不受作用域限制
多態基類指針可以指向派生類對象
避免大對象拷貝指針傳遞比對象拷貝更高效
實現復雜數據結構如鏈表、樹、圖等需要指針連接節點
延遲初始化對象可以在需要時才創建

流程圖效果:
在這里插入圖片描述

動態生命周期管理

下面舉個通俗易懂例子:

// 對象在棧上,函數結束就銷毀
void badExample() {MyClass obj;// obj 在函數返回時自動析構
}// 指針可以控制對象生命周期
MyClass* ptr = new MyClass();
delete ptr; // 手動控制銷毀
  • 可以看出這里如果使用指針的生命周期是由我們自己控制的,不受作用域限制!

  • 適用于:數據庫連接、網絡套接字、單例等需要跨函數/模塊存在的對象。

多態

下面從我們最熟悉的繼承多態來分析下:

  • 比如我們如果想寫代碼的時候,當描述的對象有些相似的特征,我們就會考慮到進行繼承多態來簡化操作,便于管理,因此這里的基類指針就是我們必不可少的了!
#include<iostream>
using namespace std;
class Animal {
public:virtual void speak() = 0;
};class Dog : public Animal { void speak() override { cout << "我是一只狗,我要叫了:"<<"汪\n"; } };
class Cat : public Animal { void speak() override { cout << "我是一只貓,我要叫了:"<<"喵\n"; } };int main(){
//  基類指針可以指向任意派生類
Animal* animals[2];
animals[0] = new Dog();
animals[1] = new Cat();for (int i = 0; i < 2; ++i) {animals[i]->speak(); 
}}

效果展示:

在這里插入圖片描述

  • 看到這就是我們非常親切的多態效果了!

  • 這是直接定義對象無法實現的!

避免大對象拷貝

這里,我們回憶下,通常比如函數傳參的時候用的要么是對象,指針,引用,而這里我們重點看對象和指針的區別。

下面先看下例子:

class BigObject
{char data[1024 * 1024]; // 1MB
};//  每次傳參都會拷貝 1MB 內存
void process1(BigObject obj)
{cout << "對象" << endl;
};//  指針只傳 8 字節地址
void process(BigObject *ptr)
{cout << "指針" << endl;
};void process2(BigObject&a){
cout << "引用" << endl;}int main()
{BigObject *p = nullptr;int s1=clock();process(p); // 指針int e1=clock();BigObject b;int s2=clock();process1(b); // 對象int e2=clock();int s3=clock();process2(b);int e3=clock();cout<<"指針耗時:"<<e1-s1<<" 消耗內存: "<<sizeof( BigObject *)<<endl;cout<<"對象耗時:"<<e2-s2<<" 消耗內存: "<<sizeof( BigObject )<<endl;cout<<"引用耗時:"<<e3-s3<<endl;}

運行效果:

在這里插入圖片描述

當然這里每次時間可能不同,這里忽視,我們可以看到對象耗時是最長的,其次是指針,而引用達到了最快。

下面解釋下原因:

  • 對象:需要拷貝構造,消耗一個對象大小,故耗時耗內存。
  • 指針:需要構建指針,故消耗指針大小。
  • 引用:直接起別名,幾乎不占內存,由編譯器在編譯期處理別名關系。

因此,這里如果條件符合,一定是選擇指針比較優的(如果對象特別大,對象的話,這不就是自己給自己找麻煩)!

實現復雜數據結構

想做個“鏈表”或“樹”,比如圖論的一些算法等具有連接關系的模型,都是需要指針來解圍的(這里順便推薦下博主的圖論專欄,講的超級詳細:圖論專欄)。

比如你要做微信好友關系鏈:

struct Person {string name;Person* friend;  // 指向下一個好友
};

沒有指針,你怎么表示“張三的好友是李四”?

這里我們經常設置進去的是指針來表示這種關系,似乎都已經成為常態了!

延遲初始化

#include <iostream>
#include <ctime>
using namespace std;
class Animal
{
public:virtual void speak() = 0;
};class Dog : public Animal
{void speak() override { cout << "我是一只狗,我要叫了:" << "汪\n"; }
};
class Cat : public Animal
{void speak() override { cout << "我是一只貓,我要叫了:" << "喵\n"; }
};class Player
{
public:Animal *Animaler = nullptr;void start(){Animaler = new Dog(); // 按需創建}
};
int main()
{Player p;//此時沒有Animaler指向的對象,也就是沒有對象產生p.start();//此時才構造處對象p.Animaler->speak();
}

效果展示:

在這里插入圖片描述

  • 對象只在真正需要時才分配內存。,真正做到了方便,節省資源!

四·直接定義對象的優勢

下面看下優勢總結:

優點說明
自動管理內存RAII,作用域結束自動析構
性能更高無間接訪問開銷
更安全不會空指針、內存泄漏(如果不用 new)

比如:

void goodExample() {MyClass obj; obj.doWork();
} // 自動調用 ~MyClass()
  • 當我們使用對象的時候(非new),它會自己出了作用域自動析構,安全感拉滿,但是new了就需要手動delete否則內存泄漏!

  • 能用棧對象就用棧對象!

五· 普通指針的壞處

指針有沒有壞處?當然有!指針就像“雙刃劍”:

  • 優點:靈活、高效、支持多態 。
  • 缺點:容易空指針、內存泄漏、野指針。

存在隱患:

非法訪問:

Book* ptr = nullptr;
ptr->read();  //  空指針崩潰!段錯誤!

忘記手動釋放:

Book* ptr = new Book();
// 忘了 delete ptr;  // 內存泄漏!

六· 現代C++怎么解決這些問題?——“智能指針”

別怕,C++11 以后有了“智能指針”,它像“自動還書機”:

#include <memory>
// 自動管理內存,不用手動 delete
unique_ptr<Book> ptr = make_unique<Book>();
ptr->read();  // 正常使用
// 函數結束,自動釋放內存,安全又省心
  • 這就類似我們普通指針,賦能添加了自動delete工作!

  • 有了智能指針,從此麻麻再也不怕我用指針操作,忘記delete了!

七· 何時使用指針 vs 直接定義對象?

下面基于上文所有的舉例以及博主總結得到下面的使用推薦方法:

場景推薦方式備注
小對象,函數內使用MyClass obj;棧分配,自動管理生命周期
需要多態(貓/狗)Base* ptr = new Derived();需配合delete手動釋放
大對象,避免拷貝func(Object* ptr)指針傳遞避免拷貝開銷
動態結構(鏈表)Node* next典型指針鏈接結構
現代C++項目unique_ptr/shared_ptr優先使用智能指針管理資源

八· 總結

用指針不是因為“高級”,而是因為“需要”,指針不是“炫技”,而是為了解決實際問題而存在的工具。

記住:

能不用指針就不用,要用就用智能指針。

如果你覺得這篇文章幫你理清了思路,歡迎點贊、收藏、轉發!

歡迎在評論區留言:

“我以前一直搞不懂指針,現在終于明白了!”

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93841.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93841.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93841.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CAMx大氣污染模擬全流程:Linux編譯/多重嵌套配置/SMOKE清單預處理/SA-DDM-PA工具應用與科研繪圖結果可視化分析

CAMx模型是一個基于大氣化學&#xff0c;針對臭氧、顆粒物和霧霾天氣過程的大氣污染物計算模型。【目標】&#xff1a;1、掌握CAMx模式的區域空氣質量模擬案例配置技術方法2、掌握SMOKE模型的CAMx模式大氣排放清單輸入準備方法3、掌握CAMx模式污染來源解析工具&#xff08;SA&a…

嵌入式學習筆記-MCU階段-DAY10ESP8266模塊

1.ESP8266概述 官方網址&#xff1a;ESP8266 Wi-Fi MCU I 樂鑫科技 (espressif.com.cn) ESP8266模塊---wifi模塊 產品特點&#xff1a; 2.ESP8266中的wifi: ESP8266EX ?持 TCP/IP 協議&#xff0c;完全遵循 802.11 b/g/n WLAN MAC 協議&#xff0c;?持分布式控制功能 (DC…

如何快速通過軟件項目驗收,第三方軟件檢測機構的重要性

在客戶和開發團隊之間&#xff0c;最后臨門一腳的項目驗收環節總容易出現各種問題&#xff0c;以至于時間無限拉長&#xff0c;久久不見結束&#xff0c;為此給大家準備了一份如何快速通過軟件項目驗收的內容來幫助大家結束持久戰。 一、項目驗收準備材料 &#xff08;一&…

洛谷做題3:P5711 【深基3.例3】閏年判斷

文章目錄題目描述輸入格式輸出格式輸入輸出樣例分析代碼題目描述 輸入一個年份&#xff0c;判斷這一年是否是閏年&#xff0c;如果是輸出 1&#xff0c;否則輸出 0。 1582 年以來&#xff0c;閏年的定義&#xff1a; 普通閏年&#xff1a;公歷年份是 4 的倍數&#xff0c;且不…

PMP證書可以掛靠嗎?怎么掛靠?

哈嘍學弟學妹們&#xff0c;作為過來人&#xff0c;今天想跟大家聊聊 PMP 證書掛靠這事兒 —— 可能不少準備考或者剛考完的同學都琢磨過&#xff0c;但學長得跟你們交個底&#xff1a;這事兒真不行&#xff0c;更別提啥掛靠費了。先說說 PMP 證書本身哈&#xff0c;它是美國 P…

91-基于Spark的空氣質量數據分析可視化系統

基于Spark的空氣質量數據分析可視化系統設計與實現 項目概述 本項目是一個基于Apache Spark的大數據分析和可視化系統&#xff0c;專門用于空氣質量數據的采集、分析、預測和可視化展示。系統采用分布式計算架構&#xff0c;結合機器學習算法&#xff0c;實現了對全國12個主要…

leetcode 2419. 按位與最大的最長子數組 中等

給你一個長度為 n 的整數數組 nums 。考慮 nums 中進行 按位與&#xff08;bitwise AND&#xff09;運算得到的值 最大 的 非空 子數組。換句話說&#xff0c;令 k 是 nums 任意 子數組執行按位與運算所能得到的最大值。那么&#xff0c;只需要考慮那些執行一次按位與運算后等于…

Git 命令使用指南:從入門到進階

目錄1. Git 基本操作1.1 添加文件到暫存區1.2 提交更改到本地倉庫1.3 查看工作區狀態1.4 查看提交歷史1.5 查看引用日志&#xff08;包括已刪除的記錄&#xff09;2. 版本回退與撤銷2.1 版本回退2.2 查看已刪除的提交記錄3. 分支管理3.1 查看分支3.2 創建并切換到新分支3.3 合并…

SQL數據庫連接Python實戰:疫情數據指揮中心搭建指南

SQL數據庫連接Python實戰&#xff1a;疫情數據指揮中心搭建指南從WHO數據集到實時儀表盤&#xff0c;構建工業級疫情監控系統一、疫情數據指揮中心&#xff1a;全球健康危機的中樞神經??疫情數據價值??&#xff1a;全球每日新增病例&#xff1a;50萬疫苗接種數據&#xff1…

參賽單位條件放寬!2025年“數據要素 ×”大賽福建分賽廈門賽區賽事有新調整

各位伙伴們 想抓住數據價值機遇 在行業賽場上嶄露頭角嗎&#xff1f; 2025年“數據要素”大賽 福建分賽廈門賽區已啟動 這份超全賽事解讀 帶你一站式摸清參賽關鍵&#xff01; 01 參賽單位要求放寬 經省分賽組委會與國家賽事組委會溝通&#xff0c;不具有獨立法人資格的…

BasicAuthenticationFilter處理 HTTP 基本認證(Basic Authentication)的核心過濾器詳解

BasicAuthenticationFilter處理 HTTP 基本認證&#xff08;Basic Authentication&#xff09;的核心過濾器詳解在 Spring Security 中&#xff0c;BasicAuthenticationFilter 是??處理 HTTP 基本認證&#xff08;Basic Authentication&#xff09;的核心過濾器??&#xff0…

Next.js 中使用 MongoDB 完整指南

1. 安裝依賴npm install mongodb # 或者使用 mongoose&#xff08;ODM&#xff09; npm install mongoose2. 數據庫連接配置使用原生 MongoDB 驅動創建 lib/mongodb.js 文件&#xff1a;import { MongoClient } from mongodbconst uri process.env.MONGODB_URI const options …

嵌入式系統教學范式演進:云端仿真平臺如何重構溫濕度監測實驗教學

在嵌入式系統開發的教學中&#xff0c;環境溫濕度監測實驗是經典的入門項目。它涉及傳感器原理、外設驅動、數據采集和通信協議等核心知識點。然而傳統實驗模式面臨硬件成本高、調試周期長、設備易損壞等痛點。學生往往因接線錯誤或代碼bug導致傳感器或開發板燒毀&#xff0c;不…

1.6萬 Star 的流行容器云平臺停止開源

什么是 KubeSphere &#xff1f; KubeSphere 是面向云原生應用的容器混合云。 KubeSphere 愿景是打造一個以 Kubernetes 為內核的云原生分布式操作系統&#xff0c;它的架構可以非常方便地使第三方應用與云原生生態組件進行即插即用&#xff08;plug-and-play&#xff09;的集成…

廣東省省考備考(第六十三天8.1)——資料分析、數量(強化訓練)

資料分析 錯題解析解析解析今日題目正確率&#xff1a;80% 數量關系&#xff1a;數學運算 錯題解析解析標記題解析解析解析今日題目正確率&#xff1a;87%

Agents-SDK智能體開發[3]之多Agent執行流程

文章目錄說明Agents SDK基礎Handoffs功能實現Handoffs簡單示例&#x1f31f; 運行結果整理&#x1f4dd; 執行過程概述&#x1f4cb; 運行結果事件一&#xff1a;分診智能體創建轉交請求事件事件二&#xff1a;轉交響應事件事件三&#xff1a;目標 Agent 響應請求并完成任務改進…

深度揭秘端口映射:原理、場景、路由映射故障,與內網IP端口映射外網工具的選擇

內網設備連不上外網&#xff1f;本地網絡如何設置端口映射提供互聯網服務&#xff1f;路由器端口映射失敗怎么辦&#xff1f;沒有公網IP如何做端口映射&#xff1f;在網絡通信領域&#xff0c;端口映射是一項至關重要的技術。在內部網絡環境中&#xff0c;每一臺設備都被分配了…

協作機器人掀起工廠革命:碼垛場景如何用數據重塑制造業命脈?

在長三角某食品包裝工廠的深夜生產線上&#xff0c;大視協作碼垛機器人正在有序碼垛&#xff0c;動作比碼垛老師傅更精準。系統推送的實時能耗報表直接顯示在廠長手機上&#xff0c;整廠能耗同比下降約32%。這不是魔法&#xff0c;這是"一切數據業務化、業務數據化"在…

LeetCode 刷題【24. 兩兩交換鏈表中的節點、25. K 個一組翻轉鏈表】

24. 兩兩交換鏈表中的節點 自己做 解&#xff1a;直接置換 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(i…

多線程向設備發送數據

需求:做一個部門授權&#xff0c;可以把所選擇部門下面的所有人的人臉信息傳到設備組里(多個設備)&#xff0c;問題在于圖片是通過Base64處理之后的&#xff0c;會導致文件名非常長&#xff0c;如果一次性傳很多數據就會超過設備的最長請求長度&#xff0c;如果不用Base64處理的…