2012-09-07 21 views
17

可能重複:
Lifetime of temporaries什麼時候臨時參數值超出範圍?

int LegacyFunction(const char *s) { 
    // do something with s, like print it to standard output 
    // this function does NOT retain any pointer to s after it returns. 
    return strlen(s); 
} 

std::string ModernFunction() { 
    // do something that returns a string 
    return "Hello"; 
} 

LegacyFunction(ModernFunction().c_str()); 

上面的例子可以很容易地改寫使用智能指針而不是字符串;我多次遇到這兩種情況。無論如何,上面的例子將在ModernFunction中構造一個STL字符串,並返回它,然後獲取一個指向字符串對象內部的C風格字符串的指針,然後將該指針傳遞給傳統函數。

  1. 在ModernFunction返回後存在一個臨時字符串對象。它何時超出範圍?
  2. 編譯器是否可以調用c_str(),破壞這個臨時字符串對象,然後將一個懸掛指針傳遞給LegacyFunction? (請記住,字符串對象正在管理c_str()返回值指向的內存......)
  3. 如果上面的代碼不安全,爲什麼它不安全,並且有沒有更好,同樣簡潔的寫法它比進行函數調用時添加一個臨時變量?如果安全,爲什麼?
+0

我剛剛編譯這個,它的工作。根據ForEveR的回答,它也應該起作用。 – 2012-09-07 17:59:27

+2

@ H2CO3,「它的工作」從來沒有證明任何東西 - 有時你只是幸運。如果你已經嘗試過它,它*不工作,那就會有所不同。 –

+0

@MarkRansom注意到「它也應該工作,根據ForEveR的答案」部分? (澄清:我知道) – 2012-09-07 18:04:23

回答

14
LegacyFunction(ModernFunction().c_str()); 

銷燬的拷貝將是full expression評估後(即,從返回LegacyFunction之後)。

n3337 12.2/3

臨時對象被銷燬作爲評價全表達式(1.9),該(詞法)包含在其中創建它們的點的最後一步 。

n3337 1.9/10

充分表達式是不是另一種表達的子表達式的表達式。如果語言構造 被定義爲產生函數的隱式調用,則爲了該定義的目的,語言構造的使用被認爲是表達式 。在 生命週期結束時生成的析構函數的調用不是臨時對象,而是隱含的完整表達式。爲了滿足表達式 所使用的語言結構的要求,應用於 結果的轉換也被認爲是完整表達式的一部分。 [實施例:

struct S { 
S(int i): I(i) { } 
int& v() { return I; } 
private: 
int I; 
}; 
S s1(1); // full-expression is call of S::S(int) 
S s2 = 2; // full-expression is call of S::S(int) 
void f() { 
if (S(3).v()) // full-expression includes lvalue-to-rvalue and 
// int to bool conversions, performed before 
// temporary is deleted at end of full-expression 
{ } 
} 

9

有ModernFunction返回之後存在的臨時字符串對象。它何時超出範圍?

嚴格來說,從來沒有範圍內。範圍是名稱的屬性,而不是對象。恰巧恰巧自動變量在範圍生存期之間有非常密切的關聯。不是自動變量的對象是不同的。

臨時對象在它們出現的完整表達式的末尾被銷燬,其中有幾個例外與此處不相關。無論如何,特殊情況下延伸臨時的一生,他們不減少它。

是否有可能爲編譯器調用c_str(),破壞此臨時字符串對象,然後通過懸空指針LegacyFunction

沒有,因爲全表達是LegacyFunction(ModernFunction().c_str())(不包括分號:感覺是pedantry),所以臨時的ModernFunction的返回值不會被銷燬,直到LegacyFunction已經返回。

如果安全,爲什麼?

因爲臨時的壽命足夠長。

通常與c_str,你不得不擔心兩件事情。首先,如果字符串被銷燬(這就是你所要求的),它返回的指針變爲無效。其次,如果字符串被修改,它返回的指針變爲無效。這裏你不擔心,但沒關係,你不需要,因爲沒有任何修改字符串。