簡體   English   中英

C++ 變量以及它們在 memory 中的存儲位置(堆棧、堆、靜態)

[英]C++ variables and where they are stored in memory (stack, heap, static)

我剛剛開始學習 C++,我想了解創建變量的不同方法以及不同關鍵字的含義。 我找不到任何真正經歷過它的描述,所以我寫了這篇文章以試圖了解發生了什么。 我錯過了什么嗎? 我有什么錯嗎?

全局變量

全局變量既不存儲在堆上,也不存儲在堆棧上。 static全局變量是非導出的(標准全局變量可以用extern訪問, static全局變量不能)

動態變量

使用指針訪問的任何變量都存儲在堆上。 堆變量使用new關鍵字分配,該關鍵字返回指向堆上 memory 地址的指針。 指針本身是一個標准堆棧變量。

{} 中未使用 new 創建的變量

存儲在堆棧中,它的大小有限,因此只能用於基元和小型數據結構。 static關鍵字意味着該變量本質上是全局的,並且與全局變量存儲在相同的 memory 空間中,但 scope 僅限於此函數/類。 const關鍵字意味着您不能更改變量。 thread_local類似於static但每個線程都有自己的變量。

登記

可以將變量聲明為register以向編譯器提示它應該存儲在寄存器中。 編譯器可能會忽略這一點,並將其應用於它認為最好的改進。 典型的用法是將索引或指針用作循環中的插入器。

好習慣

  1. 適用時默認使用const ,它更快。
  2. 警惕多線程應用程序中的static和全局變量,而不是使用thread_local或 mutex
  3. 在迭代器上使用register

筆記

在 function(非全局)中創建的任何不是staticthread_local且不是使用new創建的變量都將在堆棧中。 棧變量在memory中不要超過幾KB,否則使用new放到堆上。

完整的可用系統 memory 可用於具有static關鍵字、 thread_local關鍵字、使用new或 global 創建的變量。

使用new創建的變量需要使用delete釋放。 所有其他人在超出 scope 時都會自動釋放,除了staticthead_local和 globals 之外,它們會在程序結束時釋放。

盡管關於不應該如何使用全局變量的所有鸚鵡學舌,但不要被欺負:它們非常適合某些用例,並且比在堆上分配的變量更有效。 需要互斥鎖以避免多線程應用程序中的競爭條件。

大部分是對的。

使用指針訪問的任何變量都存儲在堆上。

不是真的。 您可以擁有指向基於堆棧或全局變量的指針。

另外值得指出的是,全局變量通常由 linker 統一(即如果兩個模塊在全局 scope 處具有“ int i ”,那么您將只有一個名為“ i ”的全局變量)。 動態庫稍微復雜了一點。 on Windows, DLLs don't have that behaviour (ie an " int i " in a Windows DLL will not be the same " int i " as in another DLL in the same process, or as the main executable), while most other platforms動態庫可以 Darwin (iOS/macOS) 有一些額外的復雜性,它具有符號的分層命名空間; 只要您使用 flat_namespace 選項進行鏈接,我剛才所說的內容就會成立。

此外,值得一提的是初始化行為; 全局變量由運行時自動初始化(通常使用特殊的 linker 功能或通過插入到main函數代碼中的調用)。 無法保證全局變量的初始化順序。 However , static variables declared at function scope are initialised when that function is first executed, and not at program start-up as you might suppose, and that feature is commonly used by C++ programmers to do lazy initialisation.

(類似的問題適用於全局對象的析構函數;最好完全避免 IMO,尤其是因為在某些平台上存在根本不會調用它們的快速終止功能。)

const 關鍵字意味着您不能更改變量。

幾乎。 const影響類型,並且根據您確切編寫它的位置而有所不同。 例如

const char *foo;

應該讀作foo是指向const char的指針,即foo本身不是const ,但它指向的東西是。 對比

char * const foo;

這表示foo是指向charconst指針。

最后,您錯過了volatile ,其目的是告訴編譯器不要對它適用的事物做出假設(例如,它不能假設在寄存器中緩存 volatile 值是安全的,或者優化訪問,或者通常優化影響易失性值的任何操作)。 希望你永遠不需要使用volatile 如果您正在做非常低級的事情,坦率地說很多人不需要 go 附近的任何地方,它通常很有用。

另一個答案是正確的,但沒有提到使用register

編譯器可能會忽略這一點,並將其應用於它認為最好的改進。

這是對的。 編譯器非常擅長選擇放入寄存器的變量(而典型的程序員不擅長這一點),以至於 C++ 委員會認為它完全沒用。

此關鍵字在 C++11 中已棄用,並在 C++17 中刪除(但仍保留以備將來使用)。

不要使用它。

您需要區分規范和實現。 該規范沒有說明堆棧和堆,因為這是一個實現細節。 他們故意談論Storage duration

如何實現此存儲持續時間取決於目標環境以及編譯器是否需要進行分配,或者這些值是否可以在編譯時確定,然后只是機器代碼的一部分(這肯定也是在內存的某些部分)。

因此,您的大多數描述都是For the target platform XY it will generally allocate on stack/heap if I do XY

C++也可以用作解釋性語言,例如可以使用完全不同的方式處理 memory 的 cling。

它可以被交叉編譯成某種字節解釋器,其中每種類型都是動態分配的。

而對於嵌入式系統,memory 的管理/處理方式可能會更加不同。

堆變量使用new關鍵字分配,該關鍵字返回指向堆上 memory 地址的指針。

如果默認operator new, operator new[]映射到malloc (或給定操作系統中的任何其他等效項),則很可能是這種情況(如果確實需要分配 object)。

但是對於嵌入式系統,可能根本沒有實現operator new, operator new[] The "OS" just might provide you a chunk of memory for the application that is handled like stack memory for which you manually reserve a certain amount of memory, and you implement a operator new and operator new[] that works with this preallocated memory,所以在這種情況下,你只有stack memory。

除此之外,您可以為某些類創建一個自定義operator new ,該運算符在某些與操作系統提供的“常規”memory 不同的硬件上分配 memory。

std::vector 將 memory 分配在 new 分配它的相同 memory 空間中,即堆,還是不是? 這很重要,因為它改變了我使用它的方式。

一個std::vector被定義為template<class T, class Allocator = std::allocator<T>> class vector; 所以有一個默認行為(由實現給出),其中向量分配 memory,對於常見的桌面操作系統,它使用像malloc這樣的操作系統調用來動態分配 ZCD69B4957F06CD818D7BF3D61980E291 但是您也可以在任何其他可尋址的 memory 位置(例如堆棧)提供使用 memory 的自定義分配器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM