C/C++基礎知識點(三)

25.STL中迭代器的作用,有指針爲何還要迭代器?

1.迭代器
iterator(迭代器)模式又稱Cursor(遊標)模式,用於提供一種方法順序訪問一個聚合對象中的各個元素,而又不需暴露該對象的內部表示。
由於迭代器的以上特性:與聚合對象耦合,在一定程度上限制了它的廣泛運用,一般僅用於底層聚合支持類,如stl中list、vector、stack等容器類以及ostream_iterator等擴展iterator。

2.迭代器與指針的區別
迭代器不是指針,是類模板,表現得像指針。它只是模擬了指針的一些功能,通過重載了指針的一些操作符:-> * ++ – 等。迭代器封裝了指針,是一個“可遍歷STL容器內全部或部分元素”的對象,本質是封裝了原生指針,是指針概念的一種提升,提供了比指針更高級的行爲,相當於一種智能指針,它可以根據不同類型的數據結構來實現不同的++ 和–等操作。
迭代器返回的是對象引用而非對象的值,所以只能輸出*取值後的值而不能直接輸出其自身。

3.迭代器產生的原因
iterator類的訪問方式就是把不同集合類的訪問邏輯抽象出來,似的不用暴露集合內部的結構而達到循環遍歷集合的效果。

26.C++中struct和class的區別

在C++中,可以使用struct和class定義類,都可以繼承。區別在於:struct的默認繼承權限和默認訪問權限都是public,而class的默認繼承權限和訪問權限都是private。此外,class還可以定義模板類形參,比如:template<class T, int i>

27.什麼是右值引用?跟左值有什麼區別?

右值引用是C++11中引入的新特性,它實現了轉移語義和精確傳遞。它的主要目的有兩個方面:
1.消除兩個對象交互時不必要的對象拷貝,節省運算存儲資源,提高效率。
2.能夠更簡潔明確地定義泛型函數。

左值和右值的概念:
左值:能對錶達式取地址、或匿名對象/變量。一般指表達式結束後依然存在的持久對象。
右值:不能對錶達式取地址,或匿名對象。一般指表達式結束就不在存在的臨時對象。

右值引用和左值引用的區別:
1.左值可以尋址,而右值不可以
2.左值可以被賦值,右值不可以被賦值,可以用來給左值賦值
3.左值可變,右值不可變(僅對基礎類型適用,用戶自定義類型右值引用可以通過成員函數改變)

詳細可參考這裏

28. STL中resize和reserve的區別

resize既分配了空間,也創建了對象,可以通過下標訪問。當resize的大小
reserve只修改capacity大小,不修改size大小,resize既修改capacity大小,也修改size大小。

reserve是容器預留空間,但並不真正創建元素對象,在創建對象之前,不能引用容器內的元素,因此當加入新的元素時,需要用push_back()/insert()函數。
resize是改變容器的大小,並且創建對象,因此,調用這個函數之後,就可以引用容器內的對象了,因此當加入新的元素時,用operator[]操作符,或者用迭代器來引用元素對象。

resize和reserve接口的共同點是它們都保證了vector的空間大小(capacity)最少達到它的參數所指定的大小。

需要注意的是:

對於resize,假如resize的大小爲n,那麼:

  • 如果n比當前的vector元素數目要小,vector的容量要縮減到resize的第一個參數大小,既n。並移除那些超出n的元素同時銷燬他們。

  • 如果n比當前vector元素數目要大,在vector的末尾擴展需要的元素數目,如果第二個參數val指定了,擴展的新元素初始化爲val的副本,否則按類型默認初始化。

  • 注意:如果n大於當前的vector的容量(是容量,並非vector的size),將會引起自動內存分配,會很耗時。

29.C++內存管理

在C++中,虛擬內存分爲代碼段、數據段、BSS端、堆區、棧區、文件映射區六部分。

  • 代碼段:包括只讀存儲區和文本區,其中只讀存儲區存儲字符串常量,文本區存儲程序的機器代碼;
  • 數據段:存儲程序中已初始化的全局變量和靜態變量;
  • bss段:存儲未初始化的全局變量和靜態變量(局部+全局),以及所有被初始化爲0的全局變量和靜態變量;
  • 堆區:調用new/malloc函數時再堆區動態分配內存,同時需要調用delete/free來手動釋放申請的內存;
  • 映射區:存儲動態鏈接庫以及調用mmap函數進行的文件映射;
  • 棧:使用棧空間存儲函數的返回地址、參數、局部變量、返回值;

30.什麼時候會發生段錯誤

段錯誤通常發生在訪問非法內存地址的時候,具體來說分爲以下幾種情況:

  • 使用野指針
  • 試圖修改字符串常量的內容

31.什麼是內存泄漏

內存泄漏是指由於疏忽或錯誤造成了程序未能釋放掉不再使用的內存的情況。
內存泄漏並非指內存在物理上的消失,而是應用程序分配某段內存後,由於設計錯誤,失去了對該段內存的控制,因而造成的內存浪費。

內存泄漏分類:

  • 1.堆內存泄漏:堆內存指的是程序運行中根據需要分配的一段內存,完成後必須通過調用delete/free刪掉,如果沒有及時釋放,那麼此後這段內存將不會被使用,就會產生Heap Leak。
  • 2.系統資源泄漏:主要指程序使用系統分配的資源,比如Bitmap、handle、socket等沒有使用相應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能降低,系統運行不穩定。
  • 3.沒有將基類的析構函數定義爲虛函數。當基類指針指向子類對象時,如果基類的析構函數不是virtual,那麼子類的析構函數將不會被調用,子類的資源沒有正確釋放,因此造成內存泄漏。

32.C++11常用的新特性

  • auto關鍵字:編譯器可以根據初始值自動推導出類型,。但是不能用於函數傳參以及數組類型的推導。
  • nullptr關鍵字:nullptr是一種特殊類型的字面值,它可以被轉換成任意其它的指針類型;而NULL一般被宏定義爲0,在遇到重載時可能會出現問題。
  • 智能指針:C++11新增了std::shared_ptr、std::weak_ptr等類型的只能指針,用於解決內存管理問題。
  • 初始化列表:使用初始化列表來對類進行初始化。
  • 右值引用:基於右值引用可以實現移動語義和完美轉發,消除兩個對象交互時不必要的對象拷貝,節省運算存儲資源,提高效率;
  • atomic原子操作用於多線程資源互斥操作;
  • 新增STL容器array以及tuple;

33.C++11中的可變參數模板

C++11的可變參數模板,對參數進行了高度泛化,可以表示任意數目、任意類型的參數,其語法爲:在class或typename後面帶上省略號。
比如:

Template<class ... T>
void func(T ... args)
{
	cout << "num is" << sizeof ...(args) <<endl;
}

func() //args不含任何參數
func(1) // args包含一個int類型的實參
func(1,2.0) //args包含一個int和一個double類型的實參
其中T叫做模板參數包,args叫做函數參數包

省略號的作用如下:

  • 聲明一個包含0到任意個模板參數的參數包
  • 在模板定義的右邊,可以將參數包展開成一個個獨立的參數

C++可以使用遞歸的函數的方式展開參數包,獲得可變參數的每個值。通過遞歸函數展開參數包,需要提供一個參數包展開的函數和一個遞歸終止函數。

比如:

#include <iostream>

using namespace std;

void print()
{
    cout << "empty" << endl;
}

template <class T,class ... Args>
void print(T head,Args ... args)
{
    cout << head << "," ;
    print(args...);
}

int main()
{
    print(1,2,3,4);
    return 0;
}

輸出:1,2,3,4,empty
參數包Args…在展開的過程中遞歸調用自己,每調用一次參數包中的參數就會少一個,直到所有參數都展開爲止,當面沒有參數時就會調用非模板函數print終止遞歸過程。

34.單核機器上寫多線程程序,是否需要考慮加鎖,爲什麼

在單核機器上寫多線程程序,仍然需要線程鎖。
因爲線程鎖通常用來實現線程的同步和通信。在單核機器上的多線程程序,仍然存在線程同步的問題。因爲在搶佔式操作系統中,通常爲每個線程分配一個時間片,當某個線程時間片耗盡時,操作系統會將其掛起,然後運行另一個線程。如果這兩個線程共享某些數據,不使用線程鎖的前提下,可能會導致共享數據修改引起衝突。

35.線程和進程的區別

  • 進程是CPU資源分配的最小單位,線程是cpu調度的最小單位
  • 進程有獨立的系統資源,而同一進程內的線程共享進程的大部分系統資源,包括堆、代碼段、數據段,每個線程只擁有一些在運行中必不可少的私有屬性,比如線程id,棧,寄存器等
  • 一個進程崩潰,不會對其他進程產生影響,而一個線程崩潰,會讓同一進程內的所有其他線程也死掉
  • 進程在創建、切換和銷燬時的開銷比較大,而線程則比較小。進程創建的時候需要分配系統資源,而銷燬的時候需要釋放資源,進程切換需要分兩步:切換頁目錄,刷新TLB以使用新的地址空間;切換內核棧和硬件上下文(寄存器);而同一進程的線程間邏輯地址控件是一樣的,不需要切換頁目錄,刷新TLB;
  • 進程間通信比較複雜,而同一進程的線程由於共享代碼段和數據段,所以通信比較容易。

36.多線程和多進程的使用場景

多進程模型的優勢是CPU,多線程模型主要優勢爲線程間切換代價較小。
因此多線程適用於I/O密集型的工作場景,因爲I/O密集型的工作場景經常會由於I/O阻塞導致頻繁的切換線程。同時, 多線程模型也適用於單機多核分佈式場景。

多進程模型,適用於CPU密集型。同時,多進程模型也適用於多機分佈式場景中,易於多機擴展。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章