gpt4 book ai didi

c++ - 如何在 C++11 lambda 中跟踪对象生命周期?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:53:16 25 4
gpt4 key购买 nike

有时,我们对捕获对象状态的 lambda 的生命周期一无所知(例如,从对象返回它,将其注册为回调而无法取消订阅等)。如何确保 lambda 不会在调用时访问已销毁的对象?

#include <iostream>
#include <memory>
#include <string>

class Foo {
public:
Foo(const std::string& i_name) : name(i_name) {}

std::function<void()> GetPrinter() {
return [this]() {
std::cout << name << std::endl;
};
}

std::string name;
};

int main() {
std::function<void()> f;

{
auto foo = std::make_shared<Foo>("OK");
f = foo->GetPrinter();
}

auto foo = std::make_shared<Foo>("WRONG");

f();

return 0;
}

这个程序打印“WRONG”而不是“OK”(http://ideone.com/Srp7RC)只是巧合(看起来它只是为第二个 Foo 对象重用了相同的内存)。不管怎样,这是一个错误的程序。当我们执行 f 时,第一个 Foo 对象已经死了。

最佳答案

延长对象生命周期

Lambda 可以捕获指向 this 的共享指针,因此只要至少有一个 lambda 存在,对象就不会消亡。

class Foo : public std::enable_shared_from_this<Foo> {
public:
Foo(const std::string& i_name) : name(i_name) {}

std::function<void()> GetPrinter() {
std::shared_ptr<Foo> that = shared_from_this();

return [that]() {
std::cout << that->name << std::endl;
};
}

std::string name;
};

http://ideone.com/Ucm2p8

通常,这不是一个好的解决方案,因为这里以非常隐含的方式延长了对象的生命周期。这是在对象之间生成循环引用的非常简单的方法。

跟踪对象生命周期

Lambdas 可以跟踪捕获的对象生命周期并仅在对象仍然存在时使用该对象。

class Foo : public std::enable_shared_from_this<Foo> {
public:
Foo(const std::string& i_name) : name(i_name) {}

std::function<void()> GetPrinter() {
std::weak_ptr<Foo> weak_this = shared_from_this();

return [weak_this]() {
auto that = weak_this.lock();
if (!that) {
std::cout << "The object is already dead" << std::endl;
return;
}

std::cout << that->name << std::endl;
};
}

std::string name;
};

http://ideone.com/Wi6O11

在没有共享指针的情况下跟踪对象生命周期

作为hvd noted ,我们不能总是确定一个对象是由 shared_ptr 管理的。在这种情况下,我建议使用以下 lifetime_tracker。它是独立的,不会影响您管理对象生命周期的方式。

struct lifetime_tracker
{
private:
struct shared_state
{
std::uint32_t count : 31;
std::uint32_t dead : 1;
};

public:
struct monitor
{
monitor() : state(nullptr) {}

monitor(shared_state *i_state) : state(i_state) {
if (state)
++state->count;
}

monitor(const monitor& t) : state(t.state) {
if (state)
++state->count;
}

monitor& operator=(monitor t) {
std::swap(state, t.state);
return *this;
}

~monitor() {
if (state) {
--state->count;
if (state->count == 0 && state->dead)
delete state;
}
}

bool alive() const {
return state && !state->dead;
}

private:
shared_state *state;
};

public:
lifetime_tracker() : state(new shared_state()) {}
lifetime_tracker(const lifetime_tracker&) : state(new shared_state()) {}
lifetime_tracker& operator=(const lifetime_tracker& t) { return *this; }

~lifetime_tracker() {
if (state->count == 0)
delete state;
else
state->dead = 1;
}

monitor get_monitor() const {
return monitor(state);
}

private:
shared_state *state;
};

使用示例

class Foo {
public:
Foo(const std::string& i_name) : name(i_name) {}

std::function<void()> GetPrinter() {
auto monitor = tracker.get_monitor();

return [this, monitor]() {
if (!monitor.alive()) {
std::cout << "The object is already dead" << std::endl;
return;
}

std::cout << this->name << std::endl;
};
}

private:
lifetime_tracker tracker;

std::string name;
};

关于c++ - 如何在 C++11 lambda 中跟踪对象生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27721052/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com