利用`std :: weak_ptr`的自杀对象实现

Que*_*tin 12 c++ shared-ptr ownership language-lawyer

我正在考虑使用"自杀对象"来模拟游戏中的实体,即能够自行删除的对象.现在,一般的C++ 03的实现(普通旧delete this)不执行任何潜在指的自杀的对象,这就是为什么我使用的其他对象std::shared_ptrstd::weak_ptr.

现在进行代码转储:

#include <memory>
#include <iostream>
#include <cassert>

struct SuObj {
    SuObj() { std::cout << __func__ << '\n'; }
    ~SuObj() { std::cout << __func__ << '\n'; }

    void die() {
        ptr.reset();
    }

    static std::weak_ptr<SuObj> create() {
        std::shared_ptr<SuObj> obj = std::make_shared<SuObj>();
        return (obj->ptr = std::move(obj));
    }

private:

    std::shared_ptr<SuObj> ptr;
};

int main() {
    std::weak_ptr<SuObj> obj = SuObj::create();

    assert(!obj.expired());
    std::cout << "Still alive\n";

    obj.lock()->die();

    assert(obj.expired());
    std::cout << "Deleted\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码似乎工作正常.但是,我想让别人去关注它.这段代码有意义吗?我是否盲目地驶入未定义的土地?我应该放弃键盘并立即开始艺术研究吗?

我希望这个问题能够充分缩小.看起来有点微小而且低级别的CR.

精度不高

我不打算在多线程代码中使用它.如果有需要,我一定会重新考虑整件事.

Yak*_*ont 3

当你有shared_ptr基于对象的生命周期时,你的对象的生命周期就是共同拥有它的对象的联合的“生命周期” shared_ptr

就您而言,您有一个内部shared_ptr,并且您的对象在该内部过期之前不会消亡shared_ptr

然而,这并不意味着您可以自杀。如果删除最后一个引用,并且任何人都已存储结果,则.lock()weak_ptr对象将继续存在。由于这是从外部访问该对象的唯一方法,因此可能会发生这种情况1

简而言之,die()无法杀死对象。最好将其称为remove_life_support(),因为在所述生命维持装置被移除后,其他东西可以使物体保持活力。

除此之外,你的设计有效。


1 你可以说“好吧,那么调用者不应该保留shared_ptr周围”——但这不起作用,因为对象是否有效的检查只有在对象shared_ptr持续存在时才有效。另外,通过公开 create 的方式shared_ptr,您无法保证客户端代码不会存储它们(意外或故意)。

如果您想要严重偏执的稳健性,基于事务的模型(您传入 lambda,并在内部对其进行操作)可以帮助解决此问题。

或者你可以和这个物体一起生活,有时会生活得太久。


考虑将这些混乱的细节隐藏在常规类型(或几乎常规)后面,这会带来pImpl令人讨厌的内存管理问题。这pImpl可能是weak_ptr具有上述语义的 a 。

然后代码的用户只需要与常规(或伪常规)包装器交互。

如果您不希望克隆变得容易,请禁用复制构造/分配并仅公开移动。

现在你讨厌的内存管理隐藏在外观后面,如果你决定你做错了,外部的pseudoRegular接口可能有不同的内容。

C++11 中的常规类型