2017-10-21 52 views
1

我發現自己寫身邊空調風格的API的C++包裝相當頻繁,浪費代碼我寫了一個公共位是這樣的:填充的std ::直接從C API的字符串

//getSomeString() wraps C api that gets some C string from somewhere 
std::string MyClass::getSomeString() 
{ 
    char buffer[BUFFER_MAX]; 
    memset(buffer, '\0', BUFFER_MAX); 
    auto result = GetCApiString(buffer, BUFFER_MAX); //C style string getter 
    return (result == NO_ERROR) ? std::string{buffer} : ""; //Copy here 
} 

,不過我真的喜歡做這樣的事情:

//getSomeString(): as before 
std::string MyClass::getSomeString() 
{ 
    DirectStringFillIterator<char> returnString; // <--HERE. Is something like this possible? 
    auto result = GetCApiString(returnString, BUFFER_MAX); 
    return (result == NO_ERROR) ? returnString.str() : ""; 
} 

這樣的事情可能嗎?

+0

如果你正在繞回返回NULL的C代碼,通常最好將C錯誤映射到C++異常。這避免了必須返回垃圾空字符串。在Rust或Swift等其他語言中,您可以將結果封裝爲「可選」,您可以在其中測試它是否包含值,但C++實際上不像這些概念那麼開放。 – tadman

+0

@tadman - 未開啓?有'boost :: optional'。而且即將在這裏'std :: optional'。 – StoryTeller

+0

@StoryTeller哦,很高興看到。我的意思是「開放」,就像在Swift的隱式解包語義中使用'!'一樣。也許「理想」是一個更好的詞。 – tadman

回答

5

std::string自C++ 11以來保證是連續的(但在我見過的每個實現中,它甚至在C++ 03中都是如此)。所以,平時你可以做

std::string MyClass::getSomeString() { 
    std::string ret(BUFFER_MAX); 
    if(GetCApiString(&ret[0], ret.size()) != NO_ERROR) return ""; 
    ret.resize(ret.find_last_of(0)-1); 
    return ret; 
} 

這避免一個副本在你的第一種方法(從本地緩存返回的字符串),但強制返回的字符串總是撥出BUFFER_MAX字節,這可能會或可能不會是一個在你的情況下下降。

+0

哦,那太棒了。非常簡單的想法,我忽略了。謝謝你的回答,我會盡快解決問題。 –

+0

而不是'&ret [0]'我個人更喜歡'ret.data()'。 –

+0

@JesperJuhl:對於一些愚蠢的原因,'std :: string :: data()'返回'const char *',與'c_str()'完全一樣。 'std :: vector :: data()',而是返回一個普通的可修改的'T *'(儘管我最終經常使用'&ref [0]',即使對於'vector',我永遠不會記得它是否是vector ''或'string'是愚蠢的'const')。 –