[英]Optimizing string creation
我有以下使用屬性設置文件名的類的模擬代碼:
#include <iostream>
#include <iomanip>
#include <sstream>
class Test {
public:
Test() { id_ = 1; }
/* Code which modifies ID */
void save() {
std::string filename ("file_");
filename += getID();
std::cout << "Saving into: " << filename <<'\n';
}
private:
const std::string getID() {
std::ostringstream oss;
oss << std::setw(4) << std::setfill('0') << id_;
return oss.str();
}
int id_;
};
int main () {
Test t;
t.save();
}
我關心的是getID
方法。 乍一看,這似乎效率很低,因為我正在創建ostringstream
及其對應的string
以返回。 我的問題:
1)由於返回const std::string
,編譯器(在我的情況下為GCC)是否可以對其進行優化?
2)有什么方法可以提高代碼的性能? 也許移動語義之類的東西?
謝謝!
1)由於返回const std :: string,編譯器(在我的情況下為GCC)是否可以對其進行優化?
除非通過引用返回,否則返回const對象沒有任何意義
2)有什么方法可以提高代碼的性能? 也許移動語義之類的東西?
id id_
不會改變,只需在構造函數中創建值,使用靜態方法可能會有所幫助:
static std::string format_id(int id) {
std::ostringstream oss;
oss << std::setw(4) << std::setfill('0') << id;
return oss.str();
}
接着:
Test::Test()
: id_(1)
, id_str_(format_id(id_))
{ }
更新:
由於id_
確實發生了更改,因此該答案對於該問題並不完全有效,我不會刪除它,因為也許有人會發現它對他的情況有用。 無論如何,我想澄清一些想法:
我的建議
一種選擇是更新id_str_
隨時領域id_
改變(你必須有一個setter id_
),因為你已經起了變化成員id_
我認為不會有任何問題,更新另一個。
這種方法允許將getID()
實現為簡單的getter(應為const,btw),而不會出現性能問題,並且字符串字段僅計算一次。
在打開文件之類的昂貴操作之前,只需創建一次ostringstream
,就根本與程序的效率無關,所以不必擔心。
但是,您應該擔心代碼中表現出的一種壞習慣。 值得稱贊的是,您似乎已經確定了它:
1)由於返回
const std::string
,編譯器(在我的情況下為GCC)是否可以對其進行優化?2)有什么方法可以提高代碼的性能? 也許移動語義之類的東西?
是。 考慮:
class Test {
// ...
const std::string getID();
};
int main() {
std::string x;
Test t;
x = t.getID(); // HERE
}
在標記為// HERE
的行上,調用哪個賦值運算符? 我們想調用移動分配運算符,但是該運算符的原型為
string& operator=(string&&);
我們實際上是在傳遞給我們的參數operator=
的類型是“引用類型的右值const string
” -即const string&&
。 const正確性規則阻止我們將const string&&
靜默轉換為string&&
,因此,當編譯器創建賦值運算符函數集時,可以在此處使用它( 重載set ),它必須排除move-assignment運算符需要string&&
。
因此, x = t.getID();
最終調用了copy -assignment運算符(因為const string&&
可以安全地轉換為const string&
),並且您制作了一個額外的副本,如果您沒有養成const
的壞習慣的話,可以避免這種情況-限定返回類型。
同樣,當然, getID()
成員函數可能應該聲明為const
,因為它不需要修改*this
對象。
因此合適的原型是:
class Test {
// ...
std::string getID() const;
};
經驗法則是: 始終按值返回,而永不按const
值返回。
您可以通過以下方式更改getID
:
std::string getID() {
thread_local std::ostringstream oss;
oss.str(""); // replaces the input data with the given string
oss.clear(); // resets the error flags
oss << std::setw(4) << std::setfill('0') << id_;
return oss.str();
}
它不會每次都創建一個新的ostringstream
。
在您的情況下,這是不值得的(就像Chris Dodd所說的那樣, 打開文件並寫入文件可能會貴10到100倍 )...只是知道。
還應考慮在任何合理的庫實現中, std::to_string
速度至少應與stringstream
一樣快。
1)由於返回const std :: string,編譯器(在我的情況下為GCC)是否可以對其進行優化?
這種做法有一個基本原理,但實際上已過時(例如,Herb Sutter建議為非原始類型返回const值)。
強烈建議使用C ++ 11將值作為非常量返回,以便您可以充分利用右值引用。
關於此主題,您可以看一下:
一種可能性是做這樣的事情:
std::string getID(int id) {
std::string ret(4, '0') = std::to_string(id);
return ret.substring(ret.length()-4);
}
如果您使用的是包含短字符串優化的實現(例如VC ++),則很有可能會顯着提高速度(使用VC ++進行的快速測試顯示,其速度大約是其4-5倍)。
OTOH,如果您使用的不包含短字符串優化的實現,則很有可能會變慢 。 例如,使用g ++運行相同的測試,所產生的代碼將慢4-5倍。
還有一點: 如果您的ID號可能超過4位數字,這不會產生相同的行為-它總是返回恰好4個字符的字符串,而不是stringstream
代碼創建的最少4個字符。 如果您的ID號碼可能超過9999,那么此代碼對您根本不起作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.