【问题标题】:Non-ownership copies of std::unique_ptrstd::unique_ptr 的非所有权副本
【发布时间】:2017-04-23 09:46:19
【问题描述】:

有两个容器:资源的所有者和非所有者。由于我只有 1 个所有者,我想我需要 unique_ptr。

class OwnershipContainer {
public:
    void add(std::unique_ptr<Obj> obj) {
        objects.push_back(std::move(obj));
    }
    Obj* get(std::size_t i) { return objects[i].get(); }
private:
    std::vector<std::unique_ptr<Obj>> objects;
};

对于非所有者容器,我必须使用哪种指针?首先想到的是原始指针。但我不能保证 Obj 的生命周期匹配或超过非所有者容器的生命周期。

class NonOwnershipContainer {
public:
    void add(Obj *obj) {
        objects.push_back(obj);
    }
    Obj* get(std::size_t i) { return objects[i]; }
private:
    std::vector<Obj*> objects;
};

int main() {
    NonOwnershipContainer nonOwnershipContainer;
    {
        OwnershipContainer ownershipContainer;
        ownershipContainer.add(std::make_unique<Obj>(1));

        nonOwnershipContainer.add(ownershipContainer.get(0));
    }
    auto pobj = nonOwnershipContainer.get(0); // dangling pointer
}

我可以将 shared_ptr 用于所有者,将 weak_ptr 用于非所有者,因此我可以检查 weak_ptr 是否已过期。但是 shared_ptr 意味着我拥有共享所有权,在我的情况下不是这样,我不需要引用计数器。

编辑:

我不想延长寿命。当所有者容器被销毁时,我想避免悬空指针。正如我上面写的,我可以使用 shared_ptr + weak_ptr。

class OwnershipContainer {
public:
    void add(std::shared_ptr<Obj> obj) {
        objects.push_back(obj);
    }
    std::shared_ptr<Obj> get(std::size_t i) { return objects[i]; }
private:
    std::vector<std::shared_ptr<Obj>> objects;
};


class NonOwnershipContainer {
public:
    void add(std::shared_ptr<Obj> obj) {
        objects.push_back(obj);
    }
    std::shared_ptr<Obj> get(std::size_t i) { return objects[i].lock(); }
private:
    std::vector<std::weak_ptr<Obj>> objects;
};

int main() {
    NonOwnershipContainer nonOwnershipContainer;
    {
        OwnershipContainer ownershipContainer;
        ownershipContainer.add(std::make_shared<Obj>(1));

        nonOwnershipContainer.add(ownershipContainer.get(0));
    }
    auto pobj = nonOwnershipContainer.get(0); // no more dangling pointer, pobj == nullptr
}

但在这种情况下,我为引用计数器付费,这在哲学上是错误的:只有一个所有者使用 shared_ptr。

【问题讨论】:

  • 反对普通std::vector&lt;Obj&gt;的论据是什么?您在 main 中所做的事情看起来非常很危险。从本质上讲,您是在尝试延长使用寿命,这意味着您弄错了所有权。
  • 如果拥有容器应该是唯一的所有者,那么所有对对象的访问都必须通过它。
  • “我不需要参考计数器。” -- 不是一种检查引用计数是否达到零的方法正是您要求的吗?
  • weak_ptr 不是为了检查,而是为了锁定对象。如果您在玩某个对象时它可能会死亡,那么检查它是否还活着是没有意义的。您将weak_ptr 分配给shred_ptr(这是锁定操作),然后检查shared_ptr。如果它还活着,它就会一直活着。它看起来正是您所需要的。
  • @Arkaniy "但实际上,引用计数器始终为 1(当对象处于活动状态时)," -- 换句话说,它并不总是 1。它可以变为 0。但是,不,当它不为零,也不总是1。你的get 返回一个shared_ptr,所以它增加了引用计数。这很好:没有它,就可以检查对象是否还活着,但在处理对象时将其从所有者集合中销毁。

标签: c++ c++14 smart-pointers


【解决方案1】:

您实际上确实拥有共享所有权:当您通过 NonOwningContainer 包含的类似指针的东西访问对象时,您必须取得所有权,否则该对象可能会在您'正在使用它。

既然你不能保证物体不会从你身下消失:

但我不能保证 Obj 的生命周期匹配或超过非所有者容器的生命周期。

那么您唯一的选择就是共享所有权。因此shared_ptrweak_ptr 是合适的方法。

另外,根据OwnershipContainerNonOwnershipContainer 的生命周期差异,请注意the interaction between std::make_shared and std::weak_ptr

【讨论】:

    猜你喜欢
    • 2016-01-30
    • 2015-05-16
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 2013-08-19
    相关资源
    最近更新 更多