2010-07-19 140 views
12

我有一些關於C++的基本問題。考慮下面的代碼,我試圖返回一個字符串。另一個C++學習時刻:從函數返回字符串

const std::string& 
NumberHolder::getValueString() { 
    char valueCharArray[100]; 
    sprintf_s(valueCharArray,"%f",_value); 
    std::string valueString(valueCharArray); 
    return valueString; 
} 

我試圖返回一個字符串的值爲一個名爲_value的類成員。不過,我得到了一個警告,我試圖傳回一個指向局部變量的指針。這當然是一件壞事。如果我現在已經足夠了解C++,這意味着當有人嘗試使用它時,我傳回的指針已經具有調用它的刪除。所以我修改:

const std::string& 
NumberHolder::getValueString() { 
    char valueCharArray[100]; 
    sprintf_s(valueCharArray,"%f",_value); 
    std::string valueString = new std::string(valueCharArray); 
    return (*valueString); 
} 

這應該在堆棧上創建一個指針,它將在該函數之外生存。這裏有兩個問題:1)它無法編譯,我不明白爲什麼(error = 無法從'std :: string *'轉換爲'std :: basic_string < _Elem,_Traits,_Ax>')和2)這似乎是一個潛在的內存泄漏,因爲我要依靠別人來調用這個人的刪除。我應該在這裏使用什麼樣的模式?

+2

這不是關於返回一個字符串;這是關於返回一個參考。一個懸而未決的參考。 – 2010-07-19 15:51:25

+0

除了你的參考問題..爲什麼const反正呢? – 2010-07-19 15:54:03

+0

std :: string valueString = new std :: string(valueCharArray); return(* valueString); 您忘記了valueString指針,這就是爲什麼不編譯: std :: string * valueString = new std :: string(valueCharArray); – Fanatic23 2010-07-19 15:56:44

回答

22

你通過在堆中分配它擊敗有std::string的地步!

僅僅通過值這樣的回報是:

std::string NumberHolder::getValueString() 
{ 
    char valueCharArray[100]; 
    sprintf_s(valueCharArray,"%f",_value); 
    return std::string(valueCharArray); 
} 

幾乎每一個編譯器現在會做return value optimization (RVO)在return語句,所以沒有副本應作出。考慮以下幾點:

NumberHolder holder; 
// ... 
std::string returnedString = holder.getValueString(); 

隨着RVO,編譯器將生成的代碼用於上述實施NumberHolder::getValueString()使得std::string是在returnedString位置構造,因此不需要拷貝。

+0

好的...這是我可以學習的東西。這裏發生了什麼事?我認爲我在函數範圍內創建了一個匿名命名的字符串,然後通過將值傳遞回來,我有效地創建了它的副本,它位於調用此函數之上的範圍內。那是對的嗎?更新:好的,我現在明白了。 – JnBrymn 2010-07-19 15:49:29

+2

是的,你正在創建一個匿名的'std :: string',但是編譯器實際上會爲這個特定的情況進行優化,並且會通過直接在返回值的位置上構造'std :: string'來消除副本。 – 2010-07-19 15:51:48

+0

有些人認爲你應該返回'const std :: string'。 – Philipp 2010-07-30 16:13:27

15

您會收到此警告,因爲您將參考返回給本地字符串,而不是本地字符串的副本。一旦函數返回,本地字符串將被銷燬,並且返回的引用無效。因此,你需要按值不參照返回字符串,:

std::string NumberHolder::getValueString() 
+0

存在內存泄漏的問題嗎?調用函數將不得不承擔刪除字符串的責任,對吧?這看起來不是最好的。 – JnBrymn 2010-07-19 15:46:37

+0

'std :: string'負責爲你服務。 – 2010-07-19 15:47:26

+5

@John:不要在堆上創建'std :: string'。只需返回本地字符串_by value_。你的第一個例子很好,只是改變返回類型。 – 2010-07-19 15:47:34

0
std::string *valueString = new std::string(valueCharArray); 

你需要創建一個指針變量從new保存結果,因爲它返回的指針。然而,理想的解決辦法真的只是要返回的值:

std::string NumberHolder::getValueString() { 
    ... 
    return std::string(valueCharArray); 
} 
3

你的第一個嘗試是正確的,如果你返回一個臨時變量,但在常引用綁定。

const std::string NumberHolder::getValueString(){} 

const std::string& val = NumberHolder::getValueString(); 

const。但你的第二次嘗試是危險的,取決於別人刪除。