オブジェクトの有効期間を延長する
ラムダは への共有ポインタをキャプチャできるthis
ため、少なくとも 1 つのラムダが存在する間、オブジェクトは停止しません。
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
ここではオブジェクトの有効期間が非常に暗黙的に延長されるため、通常、これは適切な解決策ではありません。オブジェクト間の循環参照を生成する非常に簡単な方法です。
オブジェクトの有効期間を追跡する
ラムダは、キャプチャされたオブジェクトの有効期間を追跡し、オブジェクトがまだ生きている場合にのみオブジェクトを使用できます。
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が指摘したように、オブジェクトが によって管理されていることを常に確認できるとは限りません 。そのような場合は、以下を使用することをお勧めします。これは自己完結型であり、オブジェクトの有効期間を管理する方法には影響しません。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;
};