色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C++智能指針的底層實現原理

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-09 14:32 ? 次閱讀

C++智能指針的頭文件:

#include

1. shared_ptr:

智能指針從本質上來說是一個模板類,用類實現對指針對象的管理。

template
class shared_ptr;

template
shared_ptr(Y* ptr, Deleter d);

template
shared_ptr(Y* ptr, Deleter d, Alloc alloc);

shared_ptr能解決的問題:

  1. 忘記釋放資源導致的內存泄漏;
  2. 多個指針指向同一資源時可能產生的懸垂指針;
  3. (待補充)。。。

1.1 從避免出現懸垂指針引出shared_ptr的實現原理:

先來看一個普通指針可能出現的懸垂問題:

當有多個指針指向同一個基礎對象時,如果某個指針delete了該基礎對象,對于其他指針來說,它們是無法感知的,此時則出現了懸垂指針,如果再對其他指針進行操作,則可能會導致core dump。

(core dump的原因:因為已經調用了delete,相當于已經將內存資源歸還給了系統,如果有其他地方向系統申請資源時,系統則重新分配這塊內存。此時有兩種情況:① 原始的懸垂指針調用delete,系統檢測到二次釋放,直接core dump;② 原始的懸垂指針對指針地址上的內存進行讀、寫操作,可能意外的改寫了其他程序的內容,即“踩內存”,導致發生意想不到的情況。)

int* ptr1 = new int(42);
int* ptr2 = ptr1;
int* ptr3 = ptr1;

cout << *ptr1 << endl;
cout << *ptr2 << endl;
cout << *ptr3 << endl; //沒有問題,三個指針指向同一塊內存地址

delete ptr1; //通過ptr1釋放了內存資源,ptr2和ptr3成為懸垂指針

//...

cout << *ptr2 << endl; //可能沒問題,可能有問題

普通指針出現懸垂的根本原因在于:當多個指針同時指向同一個內存資源時,如果通過其中的某一個指針delete釋放了資源,其他指針無法感知到。

解決方法自然想到了“引用計數” ---- 通過一塊額外的內存,實現對原始內存的管理。

在這塊 “控制塊” 內存中,保存當前對原始內存資源的引用計數。

普通指針多指針場景下出現懸垂指針的原因:

圖片

引入“控制塊”,保存對于基礎對象的“引用計數”,示例中有ptr1、ptr2、ptr3三個指針同時指向同一基礎對象,因此對應這個基礎對象的引用計數為 3:

圖片

當有某個指針退出作用域,或調用了delete釋放資源時,系統并非真正的釋放基礎對象,而是對引用計數減一。

那么何時才可以刪除基礎對象呢?當只有一個指針指向基礎對象的時候,就可以大大方方的通過該指針將基礎對象刪除(真正的調用delete釋放基礎對象的資源)。

圖片

對于“控制塊”的實現方式:

圖片

對“控制塊”中“引用計數”的管理:

1、構造函數:

當創建類的新對象時,初始化指針,并將引用計數設置為 1;

2、拷貝構造函數:

當對象作為另一個對象的副本時(即發生“拷貝構造”時),拷貝構造函數拷貝副本指針,并對引用計數 加1;

3、拷貝賦值運算符:

當使用“拷貝賦值運算符”(=)時,處理復雜一點:

a. 先使“左操作數”的指針的引用計數減1 (為何減一:因為該指針已經指向別的地方,則指向原基礎對象的指針個數減1), 如果減1后引用計數降為0,則釋放指針所指對象的內存資源;

b. 然后增加“右操作數”所指對象的引用計數(為何加一:因為此時左操作數轉而指向此基礎對象,則指向此基礎對象的指針個數加1);

4、析構函數:

調用析構函數時,析構函數先使引用計數減1,如果減至0則delete釋放對象。

shared_ptr類的“構造函數”使得基礎對象的引用計數遞增,shared_ptr類的“析構函數”使得基礎對象的引用計數遞減。

當最后一個指向基礎對象的shared_ptr被析構時,會調用delete釋放基礎對象的內存資源。

1.2 make_shared:

注意 make_shared 是 函數模板,不是類模板,make_shared函數模板的返回值類型是 shared_ptr。

template
shared_ptr make_shared(); //make_shared()模板函數,返回一個shared_ptr 類型的返回值

template
shared_ptr make_shared(Args&&... args);


//例如:
shared_ptr p1 = make_shared(10, '9');
shared_ptr p2 = make_shared("hello");
shared_ptr p3 = make_shared();

make_shared的優點:

  1. 效率更高;
  2. 異常安全。

make_shared的缺點:

  1. 構造函數是保護或私有時,無法使用make_shared;
  2. 對象內存可能無法及時回收。

1.2.1 優點:效率更高:

假設原始對象類型為 widget,shared_ptr的“控制塊”中需要維護的關于“引用計數”的信息包括:

  1. 強引用:用來計數當前有多少存活的shared_ptr正持有該對象,共享的對象會在最后一個強引用離開的時候釋放;
  2. 弱引用:用來記錄當前有多少個正在觀察該對象的weak_ptr,當最后一個弱引用離開的時候,共享的內部信息控制塊會被釋放。

如果通過原始的new表達式分配對象,然后傳遞給shared_ptr(即使用shared_ptr內部的構造函數),則“控制塊內存”與“基礎對象內存”是分離開的,如圖所示:

此時是兩個分配內存的動作,所以控制塊與基礎對象的內存是分離的(可能造成內存碎片)。控制塊的內存是在shared_ptr的構造函數中分配的。

auto p = new widget(); //先使用new表達式分配一個widget類型的對象

shared_ptr sp1(p); //用p去初始化sp1,此時引用計數為1
shared_ptr sp2(sp1); //用sp1去拷貝初始化sp2,此時引用計數為2

圖片

如果使用 make_shared 的方式,則只需要一次分配內存,分配出的內存結構如圖所示:

auto sp1 = make_shared();
auto sp2(sp1);

圖片

1.2.2 優點:異常安全:

可能會出現異常的情況:

//函數F的定義:
void F(shared_ptr& lhs, shared_ptr& rhs) { ... }

//調用F函數:
F(shared_ptr(new Lhs("foo")), shared_ptr(new Rhs("bar")));

C++是不保證參數求值順序,以及內部表達式的求值順序的,所以可能的執行順序如下:

1. new Lhs("foo")
2. new Rhs("bar")
3. shared_ptr
4. shared_ptr

此時,如果程序在第2步時拋出一個異常(比如out of memory等,Rhs的構造函數異常的),那么在第1步中new分配的Lhs對象內存將無法釋放,導致內存泄漏。

這個問題的核心在于 shared_ptr 沒有立即獲得new分配出來的裸指針,shared_ptr與new結合使用時是要分成兩步。

修復這個問題的方式有兩種:

(1)不要將new操作放到函數形參初始化中,這樣將無法保證求值順序:

//解決方法是先保證兩個new分配內存都沒有錯誤,并在new之后立即初始化shared_ptr:
auto lhs = shared_ptr(new Lhs("foo"));
auto rhs = shared_ptr(new Rhs("bar"));
F(lhs, rhs);

(2)更推薦的方法,是使用make_shared,一步到位 :

F(make_shared("foo"), make_shared("bar"))

1.2.3 缺點:構造函數是保護或私有時無法使用:

當我們想要創建的對象沒有公有的構造函數時,make_shared就無法使用了。

1.2.4 對象內存可能無法及時回收:

make_shared的優點是只需申請一次內存,帶來了性能上的提升。但這一性能同樣也給make_shared帶來了缺點:

智能指針的“控制塊”中保存著兩類關于“引用計數”的信息:

  1. 強引用;(strong refs)
  2. 弱引用。(weak refs)

“弱引用計數”用來保存當前正在指向此基礎對象的weak_ptr指針的個數,weak_ptr會保持控制塊的生命周期,因此有一種特殊情況是:強引用的引用計數已經降為0,沒有shared_ptr再持有基礎對象,然而由于仍有weak_ptr指向基礎對象,弱引用的引用計數非0,原本因為強引用計數已經歸0就可以釋放的基礎對象內存,現在變成了“強引用、弱引用都減為0時才能釋放”, 意外的延遲了內存釋放的時間。這對于內存要求高的場景來說,是一個需要注意的問題。

(一般情況下,程序中無需考慮這種微小的差別。)

1.3 shared_ptr實現說明:

摘自cppreference:

在典型的實現中,shared_ptr 只保有兩個指針:

  1. get()所返回的指針;(基礎對象的內存地址)
  2. 指向控制塊的指針。(控制塊對象的內存地址)

控制塊是一個動態分配的對象,其中包含:

  1. 指向被管理對象的指針或被管理對象本身;(基礎對象的內存地址)
  2. 刪除器;(Deleter,類型擦除)
  3. 分配器;(Allocator,類型擦除)
  4. 占用被管理對象的shared_ptr的數量(strong refs強引用的引用計數);
  5. 涉及被管理對象的weak_ptr的數量(weak refs弱引用的引用計數) 。

1.4 shared_ptr的線程安全性:

多線程環境下,調用不同shared_ptr實例的 成員函數是不需要額外的同步手段的(例如use_count()等成員函數),即使這些shared_ptr擁有的是同樣的對象。

但是,如果多線程訪問(有寫操作)同一個shared_ptr,則需要線程同步,否則就會有race condition發生。

shared_ptr的引用計數本身是安全且無鎖的,但shared_ptr中封裝的基礎對象的讀寫則不是。

出現這種情況的原因是:shared_ptr有兩個數據成員(指向被管理對象的指針,和指向控制塊的指針),讀寫操作不能原子化。

1.5 shared_from_this:

1.5.1 多個shared_ptr管理同一指針時的重復釋放問題:

在使用shared_ptr管理指針時,有一個原則就是要盡量避免“先new、后用裸指針初始化shared_ptr” 的方式,這是因為當有兩個或多個shared_ptr同時管理一個指針時,多個shared_ptr之間無法共享彼此的引用計數,導致可能造成double free。

異常場景示例:(兩個shared_ptr共同管理同一個裸指針)

int main() {
int *ptr = new int(42);

shared_ptr sp1(ptr);
shared_ptr sp2(ptr);

cout << sp1.use_count() << endl;
cout << sp2.use_count() << endl;
//sp1記錄的引用計數是1,sp2記錄的引用計數也是1,
//此時有兩個智能指針sp1和sp2同時管理ptr,相當于有兩個獨立的控制塊

return 0;
//此時退出作用域,sp1、sp2會分別調用delete去釋放基礎對象*ptr,
//重復釋放,導致程序段錯誤
}

由此引出一個使用shared_ptr的原則:

當我們使用智能指針管理資源時,必須統一使用智能指針,而不能在某些地方使用智能指針,某些地方使用raw pointer,否則不能保持智能指針管理這個類對象的語義,從而產生各種錯誤。

給shared_ptr管理的資源必須在分配時立即交給shared_ptr,即:shared_ptr sp(new T());,而不是先new出ptr,再在后面的某個地方將ptr賦給shared_ptr。

1.5.1 shared_from_this的使用場景:

上述的情況同樣可能會發生在 this指針 上面。

當一個類被shared_ptr管理(當使用shared_ptr管理類對象時,實際上是管理的類對象的 *this指針),且在類的成員函數中需要把當前類對象作為參數傳遞給其他函數時,就需要返回當前對象的this指針,但是,直接傳遞this指針(相當于裸指針)到類外,有可能會被多個shared_ptr所管理,造成與上面一樣的二次釋放的異常錯誤。

錯誤示例:

//C是一個可以返回類對象this指針的類:
class C {
public:
C(int b = 10) : a(b) { cout << "constructor" << endl; }
~C() { cout << "destructor" << endl; }

void show() const { cout << "a = " << a << endl; }
C* object_ptr() { return this; } //一個返回*this指針的成員函數

private:
int a;
};


int main() {
shared_ptr sp1(new C(42)); //構造一個C類對象,并由shared_ptr對此對象資源進行管理

shared_ptr sp2(sp1->object_ptr());
//在某種場景下返回類對象的this指針給其他函數,我們的本意是在原有C類對象的基礎上累加引用計數
cout << sp1.use_count() << ", " << sp2.use_count() << endl;
//sp1、sp2的引用計數都是 1

return 0;
//在退出程序前sp1、sp2的引用計數都降為0,會分別調用delete去釋放C類對象,導致重復釋放,段錯誤
}

出現上述異常的原因很簡單,類的成員函數將對象的this指針返回出去,this是一個普通指針,交給智能指針sp2管理,而sp2根本感知不到這個裸指針已經被其他智能指針sp1給管理起來了。

使用shared_ptr直接管理this指針導致“重復釋放”的原因在于:

  1. 使用智能指針管理“類對象”的本質是管理類對象的 this 指針;
  2. this指針與其他的普通裸指針并無區別,當多個shared_ptr同時管理同一個this指針時,相互之間無法感知。

C++11 引入shared_from_this,使用方式如下:

  1. 繼承 enable_shared_from_this 類;
  2. 調用 shared_from_this() 成員函數先將this指針封裝進一個shared_ptr,再將shared_ptr返回到類外供其他人使用。

使用shared_from_this 改寫上面的錯誤示例:

//首先,繼承enable_shared_from_this模板類:
//注意繼承模板類時需要先將類模板實例化,否則編譯器無法知道具體的數據類型
class C : public enable_shared_from_this {
public:
C(int b = 10) : a(b) { cout << "constructor" << endl; }
~C() { cout << "destructor" << endl; }

void show() const { cout << "a = " << a << endl; }
//C* object_ptr() { return this; } //一個返回*this指針的成員函數
//在需要返回類對象this指針的地方,調用shared_from_this成員函數先將this封裝成shared_ptr再返回
shared_ptr object_ptr() { return shared_from_this(); }

private:
int a;
};


int main() {
shared_ptr sp1(new C(42));
cout << "sp1.use_count : " << sp1.use_count() << endl;

shared_ptr sp2(sp1->object_ptr());
cout << "sp2.use_count : " << sp2.use_count() << endl;

return 0;
}

------
運行結果:

constructor
sp1.use_count : 1
sp2.use_count : 2
destructor

shared_from_this的使用公式為:

上面的例子中,雖然在類成員函數 object_ptr() 中先將this指針封裝成了一個shared_ptr,但是this指針的引用計數并沒有因此而比正常時多1,這涉及到shared_from_this的實現原理。

1.5.2 shared_from_this的實現原理:

要實現上述的shared_from_this 的功能,首先要考慮兩個設計原則:

1、首先要考慮的是:

在類對象本身當中不能存儲類對象本身的shared_ptr,否則類對象shared_ptry永遠也不會為0,從而這些資源永遠不會釋放,除非程序結束。

2、其次,類對象肯定是外部函數通過某種機制分配的,而且一經分配立即交給shared_ptr管理(強調:給shared_ptr管理的資源必須在分配時交給shared_ptr),而且以后凡是需要共享使用類對象的地方必須使用這個shared_ptr當作右值來構造生產或者拷貝產生另一個shared_ptr從而達到共享使用的目的。

基于以上兩點要求,boost中使用的是 weak_ptr 的方式來實現的。

boost 1.39.0 中是這樣實現的:

1、首先生成類A:會依次調用 enable_shared_from_this 的構造函數 以及 類A的構造函數。

enable_shared_from_this 類中有一個 weak_ptr 成員,在enable_shared_from_this構造函數中對其初始化,此時weak_ptr無效的,不指向任何對象。

2、接著,外部程序會把指向類A 對象的this指針作為初始化參數來初始化一個shared_ptr,就是下面的過程:

關鍵點在于這個shared_ptr如何初始化, shared_ptr模板類中定義了如下的構造函數:

template
explicit shared_ptr(Y *p) : px(p), pn(p)
{
boost::det
ail::sp_enable_shared_from_this(this, p, p);
}

//boost::detail::sp_enable_shared_from_this :
template
inline void sp_enable_shared_from_this(boost::shared_ptr const * ppx,
Y const * py, boost::enable_shared_from_this< T > const * pe)
{
if( pe != 0 )
{
pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
}
}


//_internal_accept_owner
template void _internal_accept_owner( shared_ptr const * ppx, Y * py ) const
{
if( weak_this_.expired() )
{
weak_this_ = shared_ptr( *ppx, py );
}
}

而在這里對 enable_shared_from_this 的成員weak_ptr進行拷貝賦值,使得整個 weak_ptr作為類對象 shared_ptr的一個觀察者。這時,當類對象本身需要自身的shared_ptr時,就可以從這個weak_ptr來生成一個了。

2. weak_ptr:

2.1 weak_ptr的特性:

  1. weak_ptr 只能從shared_ptr構建;
  2. weak_ptr 并不影響動態對象的生命周期,即其存在與否并不影響對象的引用計數(強引用的引用計數);
  3. weak_ptr 沒有重載 operator-> 和 operator* 操作符,因此不可以直接通過 weak_ptr 使用對象(必須通過weak_ptr獲取到shared_ptr后才能訪問基礎對象);
  4. weak_ptr 提供了 expired() 和 lock() 成員函數,分別用于判斷基礎對象是否已被銷毀、返回指向基礎對象的shared_ptr指針。

weak_ptr 模板類中常用的成員函數:

2.2 weak_ptr的使用場景:

  1. 當你想使用對象,但是并不管理對象,并且在需要的時候可以返回對象的shared_ptr時,則使用
  2. 解決shared_ptr的“循環引用”問題。

3. unique_ptr 與 auto_ptr:

智能指針可分為兩類:

  1. 獨占型: 如 unique_ptr,一份資源僅能由一個unique_ptr管理;
  2. 共享型: 如 shared_ptr,一份資源可以有多個shared_ptr共同管理,當沒有shared_ptr對象指向這份資源時,資源才會釋放,即基于引用計數原理。

C++11中共有四種智能指針:auto_ptr、unique_ptr、shared_ptr、weak_ptr。

所有這些智能指針都是為了管理動態分配對象的生命周期而設計的,換言之,通過保證這樣的對象在適當的時機以適當的方式析構(包括發生異常的場合),來防止資源泄漏。

auto_ptr是個從c++98中殘留下來的棄用特性,它是一種對智能指針進行標準化的嘗試,這種嘗試后來成為了c++11中的unique_ptr。

要正確的完成這個特性就需要移動語義,但在c++98中卻并沒有這樣的語義。作為一種變通手段,auto_ptr使用了 拷貝復制操作 來完成移動任務,這就導致:

  1. 可能在運行期產生異常的代碼(原始auto_ptr實例中的裸指針被置空);
  2. 某些使用限制(例如 不能在容器中存儲auto_ptr對象);

3.1 auto_ptr的核心實現代碼:

template
class auto_ptr {
private:
_Tp *_M_ptr;

public:
typedef _Tp element_type;

explicit auto_ptr(element_type *__p = 0) : _M_ptr(__p) { } //默認構造函數

auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { } //拷貝構造函數。release()成員函數會返回auto_ptr內封裝的裸指針地址

auto_ptr& operator=(auto_ptr& __a) throw() { //賦值運算符.將原始auto_ptr實例中的裸指針置為空指針
reset(__a.release());
return *this;
}

element_type* release() throw() { //當本類的實例作為參數給另外的auto_ptr賦值時,會調用實例的release成員函數,將自身內封裝的裸指針置為空,并返回資源的地址給新的auto_ptr實例
element_type *__tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}

void reset(element_type* __p = 0) throw() {
if(__p != _M_ptr) {
delete _M_ptr;
_M_ptr = __p;
}
}

};

3.2 unique_ptr的核心實現代碼:

unique_ptr的設計主要有如下兩點:

  1. 禁止拷貝構造函數、拷貝賦值運算符,即設置為=delete;
  2. 實現了移動構造函數和移動賦值運算符。

unique_ptr必須直接初始化,且不能通過隱式轉換來構造,因為unique_ptr的構造函數被聲明為explicit。

3.3 unique_ptr 的常用操作:

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3048

    瀏覽量

    74209
  • 文件
    +關注

    關注

    1

    文章

    570

    瀏覽量

    24798
  • 模板
    +關注

    關注

    0

    文章

    108

    瀏覽量

    20587
  • C++
    C++
    +關注

    關注

    22

    文章

    2114

    瀏覽量

    73785
  • 運算符
    +關注

    關注

    0

    文章

    172

    瀏覽量

    11097
收藏 人收藏

    評論

    相關推薦

    淺談C/C++里的指針

    指針CC++中的難點和重點。指針C的靈魂。我不想重復大多數書上說得很清楚的東西,只是把我看過的書中說得不清楚或沒有說,而我又覺得我理解
    發表于 06-28 10:21 ?436次閱讀

    請問STM32 C++底層封裝怎么實現

    DMA和中斷為什么使用指針?請問STM32 C++底層封裝怎么實現
    發表于 11-22 06:08

    華為內部員工培訓資料-C++課件

     C++語言中級教材講授C++語言的運用技術,包括:類、對象之間的關系、對象的存儲與布局、運算符重載、智能指針、仿函數、泛型編程,C++模式設計基本思想。 目 &
    發表于 10-16 14:10 ?0次下載
    華為內部員工培訓資料-<b class='flag-5'>C++</b>課件

    C指針_CC++經典著作

    C指針_CC++經典著作,感興趣的小伙伴們可以瞧一瞧。
    發表于 11-16 18:32 ?0次下載

    C++實驗--指針

    C++實驗--指針
    發表于 12-30 14:50 ?1次下載

    C++指針”學習建議

    C++指針”學習建議
    發表于 03-31 15:53 ?3次下載

    C++程序設計教程之指針的詳細資料說明

    本文檔詳細介紹的是C++程序設計教程之指針的詳細資料說明主要內容包括了:1. 指針的概念,2. 變量與指針,3. 數組與指針,4. 字符串與
    發表于 03-14 16:04 ?7次下載
    <b class='flag-5'>C++</b>程序設計教程之<b class='flag-5'>指針</b>的詳細資料說明

    C++指針的學習建議

     一。對于眾多人提出的c/c++指針難學的問題做個總結:
    發表于 11-07 17:13 ?8次下載
    <b class='flag-5'>C++</b><b class='flag-5'>指針</b>的學習建議

    C++封裝:this指針

    C++封裝:this指針
    的頭像 發表于 06-29 14:37 ?3500次閱讀
    <b class='flag-5'>C++</b>封裝:this<b class='flag-5'>指針</b>

    C++的異常機制底層原理與實際應用詳細說明

    我們在對 vector 做 push 操作的時候,或者對某個指針做 new 操作的時候,如果沒有做異常處理,一旦系統內存不夠用了,程序是會被 terminate 掉的。這就要求我們熟悉 C++ 異常,保證日常開發中能正確處理它。本文主要介紹
    的頭像 發表于 11-22 11:34 ?3212次閱讀

    CC++經典著作《C指針

    CC++經典著作《C指針
    發表于 01-17 09:46 ?0次下載

    C++中有函數指針還需要std::function嘛

    C/C++中可以使用指針指向一段代碼,這個指針就叫函數指針,假設有這樣一段代碼:
    的頭像 發表于 02-15 14:13 ?532次閱讀
    <b class='flag-5'>C++</b>中有函數<b class='flag-5'>指針</b>還需要std::function嘛

    底層解析C指針(一)

    指針C語言中的精髓部分,同樣也是C語言的難點所在,下面從最底層來分析C指針
    的頭像 發表于 02-15 14:47 ?915次閱讀
    <b class='flag-5'>底層</b>解析<b class='flag-5'>C</b><b class='flag-5'>指針</b>(一)

    底層解析C指針(二)

    上一篇主要討論了C指針的本質,但并沒有解釋指針的類型問題,這次我們重點來討論指針的類型與指針內存分配之間的關系。
    的頭像 發表于 02-15 14:48 ?729次閱讀
    <b class='flag-5'>底層</b>解析<b class='flag-5'>C</b><b class='flag-5'>指針</b>(二)

    C++的引用和指針

    之前的文章我們已經介紹了C++中的基本類型如int,bool和double等,除了基本類型C++還有一些更復雜的數據類型復合類型,所謂的復合類型就是通過其他類型定義的類型,本篇文章我們將會著重介紹C++的復合類型引用和
    的頭像 發表于 03-17 14:00 ?664次閱讀
    主站蜘蛛池模板: 国产亚洲精品久久777777| 97精品视频| 美女露100%全身无遮挡| 囯产精品久久久久免费蜜桃| 一本之道高清在线3线观看| 日本久久久久亚洲中字幕| 最新 国产 精品 精品 视频| 涩涩在线观看免费视频| 蜜桃传媒星空传媒在线播放| 国产精品亚洲AV毛片一区二区三区 | 狠狠狠色丁香婷婷综合久久| 大桥未久与黑人中出视频| 小草观看免费高清视频| 欧美一区二区激情视频| 久久亚洲视频| 大岛优香久久中文字幕| 亚洲AV电影天堂男人的天堂| 欧美精品色视频| 久久天堂网| 精品亚洲大全| 国产一区91| 国产精品97久久久久久AV色戒| 亚洲中文字幕日本在线观看 | 强开乳罩摸双乳吃奶视频| 国产精品久久久久久久久久久| 99久久国产露脸精品国产麻豆 | 国产激情视频在线| 成人a视频片在线观看免费| 亚洲爆乳少妇精品无码专区| 日本无修肉动漫在线观看| 欧美激情视频二区| 男人J桶女人P视频无遮挡网站| 国产精品久久久久影院嫩草| www.青青草原| 亚洲视频在线看| 人人插人人射| 欧美性FREE玩弄少妇| 欧美14videosex性欧美成人| 国产一级做a爰片久久毛片男| 国产精品久久久久久久久99热 | 亚洲国产日韩a精品乱码|