2011-08-02 11 views
6

我在用C編寫的第三方庫中有一個函數:char* fix_filename_slashes(char* path)。該函數需要傳遞一個可變的C字符串,以便它可以將路徑中的所有斜槓改爲基於操作系統的正確使用。我在Facade中使用的所有字符串都被聲明爲std::string s。我試圖簡單地使用foo.c_str()作爲期望C字符串不改變它,需要一個const char *所有其他的功能,但該功能會導致錯誤:Error: Argument of type "const char *" is incompatible with parameter of type "char *"C++:將std :: string傳遞給想要更改字符串的C函數的正確實現?

是我想出了結果:

char* tempf = const_cast<char*>(filename.c_str()); 
filename = std::string(fix_filename_slashes(tempf)); 
tempf = NULL; 

認爲「正確」或有其他(更正確?)方式來完成任務?

編輯

Whups。顯然該函數返回字符串的COPY。仍然有一些很好的答案已經給出。

+5

它有未定義的行爲寫在它的所有 –

+0

@Gene Bushuyev:你能解釋UB,所以我知道什麼是錯的? – Casey

+2

21.3.6 ... const charT * c_str()const; ....「程序不得改變任何存儲在陣列中的值的」 – fizzer

回答

7

如果字符串長度不變,可以使用指向字符串第一個字符的指針。這在C++ 03標準中是未定義的行爲,但所有已知的實現都可以正常工作,並且在C++ 11標準下明確允許。

​​

如果字符串的大小可能發生變化,您將不得不做更多的工作。

filename.resize(max_size, 0); 
append_filename_suffix(&filename[0]); 
filename.resize(strlen(filename.c_str())); 
+0

什麼標準的解決? – pm100

+0

經過一些測試後,我確定該功能不會改變長度。所以是的,看看編輯。如果返回一個副本,有點愚蠢期望非const成員。儘管如此,我無能爲力。 – Casey

1

轉換成存儲在std::vector字符的空終止序列:

template <typename Character> 
std::vector<Character> to_vector(std::basic_string<Character> const& s) 
{ 
    std::vector<Character> v; 
    v.reserve(s.size() + 1); 
    v.insert(v.end(), s.begin(), s.end()); 
    v.push_back(0); 
    return v; 
} 

用例:

std::string filename = get_filename(); 
std::vector<char> filename_cstr = to_vector(filename); 
filename = std::string(fix_filename_slashes(&filename_cstr[0])); 
+1

你能使用'迭代器,iterator'載體,而不是插入的構造,還在做着最後的'push_back'? –

+0

它會一直短寫'矢量 V(filename.begin(),filename.end());'複製串矢量,隨後'的push_back(0);' –

+0

@馬克,@Gene:是,但是這樣可以保證只發生一次分配(由'reserve'執行的分配)。如果使用範圍構造函數,則最終可能會有兩個分配(一個是範圍構造函數,另一個是'push_back')。 –

0

如果string使用單獨的緩衝器來存儲c_str串此止跌不要修改原始字符串。

更好的方法是在堆棧或堆上創建一個char緩衝區,將字符複製到它(空終止),調用fix函數,然後將緩衝區分配回字符串。

1

既然你要解決所有的麻煩,你可以只遵守C函數的要求,並將你的字符串複製到一個char數組中,然後在該函數從char數組創建一個字符串或強制對原始數據進行復制賦值串。

char* temp = new char[str.size() + 1] 
    // Force a copy of the result into another string 
    str = (const char*)fix_filename_slashes(strncpy(temp, str.c_str(), str.size() + 1)); 
    delete [] temp; 
+1

'delete [] temp;'在用'str.size()'調用'strncpy'後,'temp'不是空終止。如果'fix_filename_slashes'拋出異常也可能導致內存泄漏(可能不是,但如果是?);以及爲什麼打擾到'const char *'? (天哪,我很挑剔) – tomasz

+0

修復了代碼,但是C函數不會拋出異常,我知道應該有更多的檢查正在進行,僅用於說明目的。 –

+0

對於異常是正確的,這就是爲什麼我說我很挑剔;-) – tomasz

0

下面是另一種需要稍微設置的方法,但在此之後會自動運行。它依賴於一個臨時對象,它獲取原始字符串的副本並將修改過的字符串複製回析構函數中。顯然,所有這些複製都不會太高效,但在大多數情況下,效率並不重要。

class mutable_string 
{ 
public: 
    mutable_string(std::string & str, int maxlen = 0) : m_str(str) 
    { 
     m_buffer.resize(max(maxlen, str.length()) + 1); 
     memcpy(&m_buffer[0], str.c_str(), str.length()+1); 
    } 
    ~mutable_string() 
    { 
     m_str = m_buffer; 
    } 
    operator char*() 
    { 
     return &m_buffer[0]; 
    } 
private: 
    std::string &  m_str; 
    std::vector<char> m_buffer; 
}; 

fix_filename_slashes(mutable_string(filename)); 
相關問題