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