2014-10-20 47 views
-3

我正在寫一個函數,根據特定字符的位置將C++ string分成兩個獨立的string。但是,當我使用它返回的指針時,它們似乎是無效的。這裏有一個例子:`std :: string :: substr`返回無效指針?

#include <iostream> 
#include <string> 

bool SplitString(std::string &input, char splitChar, std::string **left, std::string **right) 
{ 
    std::string::size_type offset = input.find(splitChar); 
    if (offset == std::string::npos) return false; 
    *left = &input.substr(0, offset); 
    *right = &input.substr(offset + 1); 
    return true; 
} 

int main(int argc, char *argv[]) 
{ 
    std::string input = "Left side:Right side"; 
    std::string *left; 
    std::string *right; 

    if (SplitString(input, ':', &left, &right)) { 
     std::cout << "left = \"" << *left << "\"" << std::endl; 
     std::cout << "right = \"" << *right << "\"" << std::endl; 
    } else { 
     std::cout << "Didn't find ':' - this shouldn't happen!" << std::endl; 
    } 

    return 0; 
} 

這應該輸出如下:

left = "Left side" 
right = "Right side" 

爲什麼不工作?

+3

爲什麼不直接發送對這些函數的字符串引用?爲什麼所有的指針都瘋了? – PaulMcKenzie 2014-10-20 01:31:20

+0

這就是你得到一個右值的地址。 – 2014-10-20 01:31:25

+0

stdd :: string :: substr不返回一個std :: string *,它返回一個std :: string。你得到一個返回值的地址,當你調用你的第二個std :: string :: substr時,它將被覆蓋。只需複製字符串。擺脫所有這些指針,並使用std :: string。 – Ben 2014-10-20 01:44:46

回答

3

你並不需要在這裏指針。您可以參考leftright。可以說,你不需要參考input(你不修改它,如果你這樣做,如果你必須對同一個輸入執行其他操作,會怎麼樣?)所以要麼通過值來傳遞它(如果你打算在副本上工作)或const&(以表示不修改它的意圖)。

bool SplitString(std::string input, char splitChar, std::string& left, std::string& right) 
{ 
    std::string::size_type offset = input.find(splitChar); 
    if (offset == std::string::npos) return false; 
    left = input.substr(0, offset); 
    right = input.substr(offset + 1); 
    return true; 
} 

// ... 

    std::string left; 
    std::string right; 

    if (SplitString(input, ':', left, right)) { 

// ... 
+0

爲什麼選擇按價值輸入作爲默認值? – 2014-10-20 01:46:35

+0

'std :: string :: substr'方法構造一個新的字符串作爲結果,當退出該函數時它將被銷燬,因此,我們會在退出函數之前複製結果。順便說一句,「輸入」參數也可以作爲參考。 – 2014-10-20 01:56:05

-6

原來,當我編譯我的測試代碼g++時,它給了我一個Visual C++編譯器不給我的警告。問題是由std::string::substr返回的對象被認爲是「臨時的」,並且在函數之外使用時無效。解決方案是使用*left = new std::string(input.substr(0, offset))而不是*left = &input.substr(0, offset)。以類似的方式顯然修改*right行。

不要忘了delete當你完成他們的新對象!

這裏的工作代碼:

#include <iostream> 
#include <string> 

bool SplitString(std::string &input, char splitChar, std::string **left, std::string **right) 
{ 
    std::string::size_type offset = input.find(splitChar); 
    if (offset == std::string::npos) return false; 
    *left = new std::string(input.substr(0, offset)); 
    *right = new std::string(input.substr(offset + 1)); 
    return true; 
} 

int main(int argc, char *argv[]) 
{ 
    std::string input = "Left side:Right side"; 
    std::string *left; 
    std::string *right; 

    if (SplitString(input, ':', &left, &right)) { 
     std::cout << "left = \"" << *left << "\"" << std::endl; 
     std::cout << "right = \"" << *right << "\"" << std::endl; 
    } else { 
     std::cout << "Didn't find ':' - this shouldn't happen!" << std::endl; 
    } 

    delete left; 
    delete right; 
    return 0; 
} 
+0

當然,這只是暫時的;你從未將它分配給任何東西。 'substr'返回一個字符串。你取回了那個返回值的地址並丟棄了它自己的值。那麼爲什麼在這個世界上,你會爲此增加一個字符串?只需參考並分配'substr'的​​結果。讓'string'完成它的工作併爲你處理內存分配。另一方面,有更好的方法來分割一個字符串。使用'std :: getline'。 – 2014-10-20 01:23:57

+0

請解釋一下這段代碼的作用:'刪除左邊,右邊;' – PaulMcKenzie 2014-10-20 01:30:26

+3

請注意''刪除左邊,右邊''不會同時刪除兩個指針 – 2014-10-20 01:30:35