我目前正在試驗以下方法來完成處理一些資料(偽代碼)。
void run_processing(container datas)
{
// runs some conversion on data and sends it somewhere.
}
struct process_item
{
container datas;
process_item(const char* data)
{
datas.add(data);
}
~process_item()
{
run_processing(datas);
}
operator <<(const char* data)
{
datas.add(data);
}
}
process_item create_item(const char* data)
{
process_item item(data);
// Possible additional calls to setup item.
return item;
}
在我的測驗中,這允許通話。
create_item("my_data") << "additional data" << "even more data";
// Once this piece executes the destructor for process_item is assumed to be called.
偽代碼并沒有真正顯示出預期的好處,但這不是我的問題。
我嘗試這樣做是因為我有一些限制;直到所有資料都輸入后才能開始處理,除了 process_item 的作用域結束時,不知道什么時候是這種情況。為簡單起見,假設我不能在添加最后一個資料后呼叫其他方法或添加標志。
是否可以假設在預期時間呼叫解構式,或者根據優化級別和編譯器選擇不同的選項是否風險太大?
澄清
“在正確的時間”的意思是在下一行之前,在呼叫create_item執行之后的那一行。
uj5u.com熱心網友回復:
你的策略的一個問題是,在銷毀時,你沒有(安全)能力
拋出例外報告錯誤,或
回傳結果
從解構式拋出例外是一個非常非常糟糕的主意,因為如果其他人拋出例外,解構式會在堆疊展開期間運行,而如果您在堆疊展開期間拋出例外,則程式將終止。
有很多方法可以解決它,但它們涉及......在堆疊展開期間不拋出例外。所以任何錯誤都會丟失。
此外,您可能會遇到例外導致您打算執行的操作部分準備,然后執行的可能性。這可能會破壞資料的一致性。
處理此問題的一種方法是:
[[nodiscard]] process_item& operator <<(const char* data)
{
datas.add(data);
return *this;
}
然后提供一個operator error_code()或任何東西來強制用戶將整個<<鏈分配給一個錯誤變數。就是operator error_code()導致代碼被執行。
在這種模型下,在 行拋出的例外<< 不會導致操作運行,因為operator error_code()跳過了。
可悲的是,[[nodiscard]]不是C 11.
...
除此之外,是的,臨時物件在創建它們的完整運算式結束時被銷毀。有一些涉及省略和引數傳遞的例外,但這些不太可能適用于您描述的代碼。
當你寫了一個解構式時,你需要遵守規則 5。這意味著你需要洗掉或實作一個復制/移動賦值/建構式(洗掉是一個簡單的選擇)。
如果您洗掉復制/移動操作,您可能會在 中遇到問題create_item,因為無法保證 NRVO 省略。它會在C 17如果您使用 RVO 省略(因為現在可以保證)。另一種選擇是使您的類移動友好(包括移動“準備執行”狀態),以便移動的實體不運行該操作。
我強烈建議您阻止復制操作。很容易意外地為您想要運行一次的某些操作制作 3 個副本。能夠復制到一半的操作是很酷的,但是 C 復制語意有點太容易參與了:如果您希望能夠復制但不會意外發生,請添加一個.copy()const回傳純右值的方法.
uj5u.com熱心網友回復:
glog 做這樣的事情,在解構式中運行行程就可以了。如果你想讓 desctuctor 運行得快,在 anthor 執行緒中運行行程。
LOG(INFO) << "hello" << "world";
LOG(INFO) 是一個宏,它創建一個流物件accpet訊息,當物件被破壞時,它會將訊息寫入日志檔案。閱讀 glog 的代碼可能對你有幫助
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/333421.html
下一篇:為什么我們應該在<algorithm>頭的函式之前使用std命名空間而不應該在<cmath>頭的函式之前使用它?
