std::unique_ptr vs std::shared_ptr vs std::weak_ptr vs std::auto_ptr vs 原始指针 (注意:std::auto_ptr已被弃用,不建议在新代码中使用)

26

相较于使用原始指针所采用的一些高级技术(但不仅限于此),每种智能指针的等效用法是什么?

我的理解很少,但从我所了解到的:

  • 原始指针:只有在您确实非常非常非常非常地知道自己在做什么并已经在接口后小心隐藏了用法时才使用。
  • std::auto_ptr:已过时,不要使用。
  • std::unique_ptr:单例指针,通过赋值转移所有权。
  • std::shared_ptr:引用计数指针,在分配时不会转移所有权,但会增加其引用计数。当所有引用离开范围或明确调用std::shared_ptr::reset时,将调用底层的deallocater
  • std::weak_ptr:std::shared_ptr的子类型,不会增加引用计数,并在其父std::shared_ptr不存在时无效。可能返回无效引用。在使用之前请务必检查。

等效的原始指针示例

引用计数、缓存实现:std::map<std::string, std::pair<long, BITMAP*> > _cache;

具有所有权转移的单例:

class Keyboard {
public:
//...
    static Keyboard* CreateKeyboard();
    ~Keyboard();
//...
private:
//...
    Keyboard();
    static Keyboard* _instance;
//...
};

聚合容器,无所有权:空间分割图和树,迭代容器等。

组合容器,有所有权:大型对象。

-- 编辑--

在我的工作中,我遇到了一个有趣的情况,DeadMG指出智能指针应该被用作易于抽象的资源管理工具; 那么对于不能在声明时在堆上创建,而必须在稍后时间创建的文件范围对象呢?


2
我不明白你在问什么。如何使用原始指针实现智能指针行为? - Neil Kirk
1
我不知道这个问题是什么,但如果你把unique_ptr称为单例指针,我怀疑你在这里对单例有完全不同的理解。 - Puppy
1
@Casey:您可能需要考虑将其编辑到您的问题中。 - Puppy
1
@Casey:不,每个资源只有一个unique_ptr。即使你开始使用自定义删除器来执行除完全销毁资源之外的其他操作,这也可能会有一些灵活性。 - Puppy
1
@DeadMG 哦,所以这是一对一的关系,而不是 std::shared_ptr 的一对多。 - Casey
显示剩余4条评论
1个回答

5

每个智能指针都应该替代哪个习语?

所有涉及销毁所指向资源的习语,不论是过去还是现在。换句话说,几乎所有涉及原始指针的习语都可以替换为智能指针。我想不到任何不涉及销毁所指向资源的原始指针习语。其他用法实际上并不是习语,只是“使用指针”而已。


聚合容器不会销毁它们所指向的资源,它们只是从列表中移除。这是我在学习智能指针时关注的主要问题,哪种智能指针可能成为这种用法的合适候选? - Casey
@Casey:如果他们不销毁所指向的资源,那么他们为什么要使用智能指针呢?智能指针是用来销毁东西的。 - Puppy
好的,这就是我感到困惑的原因。我读过的每个支持智能指针的人都强烈反对以任何形式使用裸指针,并应该用智能指针替换。 - Casey
5
这仅适用于可摧毁的资源。原始指针仍然是必不可少的观察者,就像引用一样。 - Puppy
@DeadMG,即使作为观察者,原始指针不是过时的吗?除非处理使用C数组的旧代码,否则引用或迭代器都可以完成工作。 - VF1
2
@VF1 你不能重新设置引用。如果观察者可能为空,使用引用是行不通的。 - Casey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接