2015-09-05 56 views
7

我知道下面的代碼將創建一個字符數組,並保持在內存中,直到節目結束:分配一個字串的std :: string

char* str = "this is a string"; 

對於這一說法,創建一個本地陣列字符,將被釋放時,STR超出範圍:

char str[] = "this is a string"; 

我很好奇的是,當我把它寫這樣會發生什麼:

std::string str = "this is a string"; 

str應該在自己的內存(本地)中創建一個字符串的副本,但是字符串本身又如何呢?它是否具有程序的生命週期,或者當str超出範圍時它將被釋放?

+5

字符串文字具有「靜態」存儲持續時間,所以它**總是**在程序的整個生命週期中都存在。 –

+0

'std :: basic_string'不擁有文字,因此它的生存期不是由'str'確定的。 – edmz

回答

6

當你寫這個

std::string str = "this is a string"; 

C++應該找到的std::string這需要const char*,要求它做一個臨時對象的構造,調用拷貝構造函數來複制臨時到str,然後銷燬臨時目的。

但是,它允許C++編譯器跳過臨時對象的構造和析構,所以結果的優化是一樣的

std::string str("this is a string"); 

但對於字符串字面本身?它是否具有程序的生命週期,或者當str超出範圍時它將被釋放?

以這種方式使用時,字符串字面本身無法訪問您的程序。通常情況下,C++將它放在與其他字符串文字相同的片段中,用它傳遞給std::string的構造函數,並忘記它。允許優化器消除所有字符串文字中的重複項,包括僅在其他對象的初始化中使用的重複項。

+7

IIRC,在這裏可以不調用'operator =',因爲這需要在兩邊都構建一個對象。相反,用'='初始化調用複製構造函數。 – Oberon

+0

@Oberon你是對的,它是一個複製構造函數。我確定了答案,非常感謝! – dasblinkenlight

0

一些你最初的陳述是不完全正確的:

對於char *char []例如,在兩種情況下,變量本身,str仍然在範圍和訪問,直到它是否在全局命名空間被聲明的程序結束。

如果它在函數或方法的作用域中聲明,那麼在範圍保持活動狀態時它是可訪問的。兩個都。

至於用於存儲實際文字字符串的內存實際發生了什麼,這是未指定的。只要結果符合C++標準,特定的C++實現就可以以任何更方便的方式管理運行時內存。就C++而言,您沒有訪問str對象所使用的內存,而只是引用str對象本身。

當然,你可以自由地拿一個原生char *指針,指向str中的一個字符。但是,指針是否有效直接與底層對象的範圍相關聯。當對應的str對象超出作用域時,指針不再有效,訪問指針的內容變爲未定義的行爲。

請注意,在str位於全局命名空間的情況下,str的範圍是程序的生命週期,因此該點沒有實際意義。但是,str在本地範圍內,並且超出範圍時,使用指針變成未定義的行爲。底層內存會發生什麼變化是無關緊要的。 C++標準並沒有真正定義底層實現中內存應該或不應該發生什麼,但是什麼是或者不是未定義的行爲。

基於此,您幾乎可以自己找出std::string個案的答案。這是同一件事。您正在訪問std::string對象,而不是基礎內存,並且適用相同的原則。

但是請注意,除了範圍問題外,std::string對象的一些方法(但並非全部)也被指定爲使所有現有的直接指針和迭代器都無效到其內容,因此這也會影響是否a將char *指定給std::string中的其中一個字符仍然有效。

3

大多數操作系統將劃分您的程序內存分爲幾個部分

  • 堆棧
  • 的堆
  • 數據段
  • BSS段
  • 代碼段

你已經知道堆棧和堆,但那其他人呢?

代碼段保持二進制形式的所有操作。

現在它變得有趣: 讓我們來看看下面的代碼:

int x; 
class Y{ static int y; }; 
int main(){ 
    printf("hello world"); 
    return 0; 
} 

哪裏的程序分配xy?他們不是本地或動態分配的,所以在哪裏?

數據段保留所有靜態變量和全局變量,當程序被加載時,這個段保留足夠的字節來保存所有的靜態變量和全局變量。如果變量是一個對象,當程序上升時,它將爲所有變量(包括對象)分配足夠的字節。在main之前,程序調用每個全局對象的構造函數,並且在main完成之後,它以相反的順序調用每個對象析構函數,它調用構造函數。

BSS段是數據段的一個子集,它保留全局指針和靜態指針,這些指針是null-intitalized的。

因此,假設字符串文字沒有被優化掉,程序將其存儲在數據段中。只要程序存在,它就會繼續存在。此外,如果它是一個字符串文字,很可能你甚至可以在exe文件中看到它!作爲文本文件打開該exe文件。一路上的一些點,你會看到清楚的字符串。

現在怎麼辦 std::string str = "hello world";

這是一個時髦的情況。 str本身生活在堆棧上。實際的內部緩衝區位於堆上,但用於分配字符串的字符串字面值存在於數據段中,並且代碼段中生存的代碼值爲hello world。不用說,如果我們要組裝程序,我們需要用我們自己的手來構建這個生態系統。

0

我會提供一個櫃檯問題:你爲什麼在意?

的C++標準規定,當涉及到的實現基本上是被稱爲AS-如果規則語言的行爲,和第一核心原則:

§1.9程序執行

1/本國際標準中的語義描述定義了一個參數化的非確定性抽象機器。本國際標準沒有要求符合實施的結構。特別是,他們不需要複製或模擬抽象機器的結構。相反,需要符合實現來模擬(僅)抽象機器的可觀察行爲,如下所述。


你的情況:

std::string str = "this is a string"; 

有各種有效的方案:

  • 你不使用str之後?那麼這整個代碼部分可能會完全消失
  • 您以後立即將'T'分配給str[0]?那麼這兩個可能會被合併爲std::string str = "This is a string";
  • ...

,並沒有保證,以什麼編譯器會做。它可能取決於你使用的編譯器,你使用的標準庫實現,你正在編譯的體系結構/操作系統,甚至是傳遞給編譯器的參數......

因此,如果你想知道你的案例中的,您將不得不檢查生成的機器碼。問coliru,爲以下代碼:

#include <string> 

int main(int argc, char** argv) { 
    std::string str = "this is a string"; 
} 

鏘產生在IR如下:

@.str = private unnamed_addr constant [17 x i8] c"this is a string\00", align 1 

這進而給出了以下組件:

.L.str: 
    .asciz "this is a string" 
    .size .L.str, 17 

所以你有它,對於這些特定的條件,"this is a string"將在二進制中是原樣並將被加載到只讀存儲器中。它將留在進程的地址空間中,直到結束,操作系統可能會根據內存壓力將其分頁或不分頁。

相關問題