我知道如果必須在lambda中爲回調調用成員函數,我會在lambda中捕獲它,並且它工作正常。 但是我最近看到了一些崩潰,看起來成員函數在被這個指向的對象已經被銷燬之後被訪問。 簡而言之,在關閉時,對象被銷燬,但指針在lambda中傳遞,lambda被訪問並導致崩潰。在lambda中捕獲此選項的替代方法[C++]
所以,我試圖理解社區通常在這種情況下做什麼。我找不到太多,但我認爲shared_ptr可能是一個選項。
任何建議/線索將不勝感激,以幫助我理解和實施一個替代方案。
我知道如果必須在lambda中爲回調調用成員函數,我會在lambda中捕獲它,並且它工作正常。 但是我最近看到了一些崩潰,看起來成員函數在被這個指向的對象已經被銷燬之後被訪問。 簡而言之,在關閉時,對象被銷燬,但指針在lambda中傳遞,lambda被訪問並導致崩潰。在lambda中捕獲此選項的替代方法[C++]
所以,我試圖理解社區通常在這種情況下做什麼。我找不到太多,但我認爲shared_ptr可能是一個選項。
任何建議/線索將不勝感激,以幫助我理解和實施一個替代方案。
在C++中,您有責任追蹤對象的生命週期。
這意味着你必須跟蹤掌握指針和其他事物引用的事物的生存期,並確保它們不會像那些事一樣長壽。
您的任務失敗。你通過了捕獲指向周圍物體的指針的lambdas,就好像它們在哪裏糖果一樣,而不是直接插入對象的內部。
通過噴灑共享指針來解決生命期問題通常是一個壞主意。讓物體的壽命變得更模糊可能會減少立即崩潰的事件,但物體壽命的模糊不清使得程序無法工作。這個模糊的球或者擴展到包含你現在無法真正關閉的整個程序,或者它自己回到自身並自我延續,從而泄漏資源。
共享指針可用於狹義的情況下,在這種情況下,您擁有最佳建模爲共享所有權的定義的生命週期關係。這與「我的對象在指針前離開,所以我應該嘗試共享指針!」完全不一樣。你有一個對象生命期問題。你嘗試共享指針。現在你有兩個問題:原始對象生命期問題和共享指針問題。
回調是一個例子,您需要嚴格的生命週期規則。你回調多久了?你什麼時候停止?您如何緊急回收資源?你如何取消註冊回調?等
我已經寫回調系統,使用共享和弱指針。他們並不完美。這是我在google中找到的一個:broadcaster。聽衆存儲令牌時會說「繼續跟我說話」,當他們離開廣播公司時,他們就停止了。
鎖定的weak_ptr仍然是最可靠和最簡單的方法,可以消除訂閱者在消息隊列中未實現的回調潛伏期間消失的情況。 –
@RichardHodges請注意,'broadcaster
這是我用於處理訂閱的模式。使用鎖定的weak_ptr
消除了交叉案件的風險。
#include <memory>
#include <chrono>
#include <thread>
#include <mutex>
using namespace std::literals;
// some external service that will send us events in a callback.
// normally of course we'd have some means to turn these off too.
// However for this demo we'll ignore that for now
void subscribe_for_events(std::function<void()> f);
struct might_go_away : std::enable_shared_from_this<might_go_away>
{
static std::shared_ptr<might_go_away> create() {
auto p = std::make_shared<might_go_away>();
p->start();
}
might_go_away() {}
private:
using mutex_type = std::mutex;
using lock_type = std::unique_lock<mutex_type>;
// handy helper to deliver a weak pointer to ourselves
auto weak_self() { return std::weak_ptr<might_go_away>(shared_from_this()); }
// do startup things here, like subscribing to other services etc
void start() {
subscribe_for_events([this, weak = this->weak_self()]
{
// don't touch 'this' until we have successfully locked the weak ptr
if (auto self = weak.lock()) {
// we know we're alive. the variable 'self' will hold the strong count > 0
// this is a good place to take locks
handle_event(lock_type(mutex_));
}
});
}
void handle_event(lock_type) {
// do things when notified by some event source.
// we are safe here. `this` will not go away and we own the mutex
// we will release the lock when this function exits through RAII.
// PLUS, because the lock was moved in, we own it. We can release it early if we wish.
}
mutex_type mutex_;
};
當然在生產代碼之中,shared_ptr
將被包裹在面向消費者的手柄類。
我們希望儘可能使用價值語義。
struct active_thing
{
using implementation_class = might_go_away;
using implementation_type = std::shared_ptr<implementation_class>;
active_thing() : impl_(implementation_class::create()) {}
// methods here
private:
implementation_type impl_;
};
int main()
{
{
auto a = active_thing();
std::this_thread::sleep_for(5s);
}
}
你能發表一段代碼嗎? –
你可以從'std :: enable_shared_from_this'繼承,使用'shared_from_this()'得到一個共享指針並捕獲一個'std :: shared_ptr'如果你想確保該對象仍然存在或者是一個'std: :weak_ptr'如果你想在做任何操作之前檢查它是否存在。 – skypjack
我會說@TheEyesightDim。我們可以得到[mcve]嗎? – user4581301