我有一個多shared_ptrs指向它的物件,它use_count在關聯控制塊中的參考計數大于 1。
現在,我想解構 Object,但我不知道所有這些在哪里shared_ptrs,所以在解構 Object 之前我無法找到和解構它們。
如果我只是解構物件,它會使那些shared_ptrs變得懸空。因此,在這種情況下,如何洗掉use_count大于1但不知道其全部的Object shared_ptrs?
感謝您的任何建議!
uj5u.com熱心網友回復:
如何洗掉關聯 use_count 大于 1 的物件?
通過將使用計數減少到 0。這可以通過銷毀或重新分配當前指向物件的共享指標來實作。
但我不知道那些 shared_ptrs 在哪里
然后你必須解決阻止你知道所有這些指標的問題。
或者,您可以考慮這些指標的存在可能是有原因的,并且可能不應該洗掉該物件,因為它顯然已被程式的某些部分使用。
uj5u.com熱心網友回復:
如果您有權訪問Object類代碼并且可以修改它,那么您可以執行以下步驟(之后您可以直接跳到最終代碼):
創建
Fields包含 original 的所有欄位的特殊結構Object。存盤
Fields為堆分配的指標欄位p_。在原始
Object類中,將所有原始欄位作為指向Fields堆分配物件欄位的參考。添加
destroyed_標記Object已被銷毀的bool 標志。該標志true在第一次呼叫解構式后變為。在每個方法中檢查
destroyed_不為真,否則拋出例外。因為當物件已經被銷毀時,沒有任何方法可以使用。您也可以只顯示帶有一些錯誤的訊息,而不是拋出例外并從方法回傳而不做任何事情。由您決定如何處理此錯誤。第一次呼叫的內部解構式像往常一樣進行所有清理。并標記
destroyed_為true。由于 destroy_ 已經為真,對解構式的第二次呼叫應該只是默默地退出。所有復制建構式和賦值運算子都應該像往常一樣實作。下面的代碼示例。
要在釋放所有共享指標之前洗掉物件,只需呼叫ptr->~Object();解構式,這里ptr是任何共享指標,或使用便利函式std::destroy_at,如下所示std::destroy_at(ptr.get());。
在下面的代碼中,如果 lastDoSomething()沒有被呼叫(嘗試將其注釋掉),那么程式將毫無例外地完成,盡管會顯示關于第二次呼叫解構式的警告。
在線試試吧!
#include <iostream>
#include <memory>
class Object {
public:
Object()
: p_(new Fields{}), f0_(p_->f0_), f1_(p_->f1_) {}
Object(Object const & o)
: p_(new Fields{}), f0_(o.f0_), f1_(o.f1_) {}
Object & operator = (Object const & o) {
f0_ = o.f0_;
f1_ = o.f1_;
return *this;
}
void DoSomething() {
if (destroyed_)
throw std::runtime_error("Object already destroyed!");
f0_ = 1;
f1_ = std::to_string(f0_) " ";
std::cout << "DoSomething: '" << f1_ << "'" << std::endl;
}
~Object() {
if (destroyed_) {
std::cout << "Called destructor of destroyed object..."
<< std::endl;
return;
}
// Process fields cleanup here...
delete p_;
p_ = nullptr;
destroyed_ = true;
}
private:
struct Fields {
int f0_ = 0;
std::string f1_;
};
Fields * p_ = nullptr;
bool destroyed_ = false;
int & f0_;
std::string & f1_;
};
int main() {
try {
std::shared_ptr<Object> o0 = std::make_shared<Object>();
{
std::shared_ptr<Object> o1 = o0;
o1->DoSomething();
o1->DoSomething();
// Call destructor when you don't need object.
// Even if some shared_ptrs still use it.
o1->~Object();
}
o0->DoSomething();
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
輸出:
DoSomething: '1 '
DoSomething: '1 2 '
Called destructor of destroyed object...
Exception: Object already destroyed!
與上面類似的代碼也可以使用 C 17 std::optional而不是堆指標來實作,這個解決方案更好,因為它不使用任何堆分配,所有欄位都位于物件的主體內(即堆疊分配)。
在線試試吧!
#include <iostream>
#include <memory>
#include <optional>
class Object {
public:
Object()
: p_(Fields{}), f0_(p_->f0_), f1_(p_->f1_) {}
Object(Object const & o)
: p_(Fields{}), f0_(o.f0_), f1_(o.f1_) {}
Object & operator = (Object const & o) {
f0_ = o.f0_;
f1_ = o.f1_;
return *this;
}
void DoSomething() {
if (destroyed_)
throw std::runtime_error("Object already destroyed!");
f0_ = 1;
f1_ = std::to_string(f0_) " ";
std::cout << "DoSomething: '" << f1_ << "'" << std::endl;
}
~Object() {
if (destroyed_) {
std::cout << "Called destructor of destroyed object..."
<< std::endl;
return;
}
// Process fields cleanup here...
p_ = std::nullopt;
destroyed_ = true;
}
private:
struct Fields {
int f0_ = 0;
std::string f1_;
};
std::optional<Fields> p_;
bool destroyed_ = false;
int & f0_;
std::string & f1_;
};
int main() {
try {
std::shared_ptr<Object> o0 = std::make_shared<Object>();
{
std::shared_ptr<Object> o1 = o0;
o1->DoSomething();
o1->DoSomething();
// Call destructor when you don't need object.
// Even if some shared_ptrs still use it.
o1->~Object();
}
o0->DoSomething();
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
輸出:
DoSomething: '1 '
DoSomething: '1 2 '
Called destructor of destroyed object...
Exception: Object already destroyed!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/378901.html
下一篇:如何從定義它的類回傳結構?
