问题标签 [smart-pointers]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
6 回答
255 浏览

c++ - Automatically converting an A* into a B*

Suppose I'm given a class A. I would like to wrap pointers to it into a small class B, some kind of smart pointer, with the constraint that a B* is automatically converted to an A* so that I don't need to rewrite the code that already uses A*.

I would therefore want to modify B so that the following compiles...

Note that B inheriting from A is not an option (instances of A are created in factories out of my control)...

Is it possible?

Thanks.

0 投票
3 回答
1425 浏览

c++ - 指向 auto_ptr 而不是经典双指针的指针

我对智能指针很陌生,并试图重构一些现有代码以使用 auto_ptr。我的问题是关于双指针和它们的 auto_ptr 等价物,如果这有意义的话。

我有一个接受双指针作为参数的函数,并且该函数为其分配资源:

然后像这样使用这个函数:


我想使用 auto_ptr 来避免显式调用 delete 。以下是正确的吗?

进而

谢谢。

0 投票
2 回答
1270 浏览

c++ - 如何将 boost::shared_ptr (或另一个智能指针)附加到对象父级的引用计数器?

我记得以前遇到过这个概念,但现在在谷歌上找不到。

如果我有一个 A 类型的对象,它直接嵌入了 B 类型的对象:

我怎样才能有一个智能指针B,例如boost::shared_ptr<B>,但使用引用计数A?假设它自己的一个实例A是堆分配的,我可以安全地使用enable_shared_from_this.

0 投票
3 回答
183 浏览

c++ - 如何强制用户仅使用“新”创建从我的类派生的对象?

为了实现引用计数,我们使用了一个IUnknown-like 接口和一个智能指针模板类。该接口实现了所有引用计数方法,包括Release()

智能指针模板类有一个复制构造函数和一个赋值运算符,它们都接受原始指针。因此用户可以执行以下操作:

并且程序运行到未定义的行为 - 对象被创建时引用计数为零,智能指针被构造并将其碰撞到 1,然后函数返回,智能指针被破坏,调用Release()导致delete堆栈分配的变量。

用户还可以执行以下操作:

再一次没有创建的对象newdeleted。处于最佳状态的未定义行为。

有没有办法改变IUnknownLike接口,以便用户被迫使用new创建所有派生的对象IUnknownLike- 直接派生和间接派生(在最派生和基础之间的类)?

0 投票
6 回答
2882 浏览

c++ - 如何处理未能释放包含在智能指针中的资源?

当表示资源的对象包含在共享指针中时,应如何处理资源释放期间的错误?

编辑1:

用更具体的术语来说明这个问题:许多 C 风格的接口具有分配资源和释放资源的功能。示例是用于 POSIX 系统上的文件描述符的 open(2) 和 close(2),用于连接到 X 服务器的 XOpenDisplay 和 XCloseDisplay,或用于连接到 SQLite 数据库的 sqlite3_open 和 sqlite3_close。

我喜欢将此类接口封装在 C++ 类中,使用 Pimpl 习惯用法隐藏实现细节,并提供返回共享指针的工厂方法,以确保在没有对资源的引用时释放资源。

但是,在上面给出的所有示例和许多其他示例中,用于释放资源的函数可能会报告错误。如果这个函数被析构函数调用,我不能抛出异常,因为通常析构函数不能抛出。

另一方面,如果我提供了一个公共方法来释放资源,那么我现在有一个具有两种可能状态的类:一种是资源有效,另一种是资源已被释放。这不仅使类的实现复杂化,而且还存在错误使用的可能性。这很糟糕,因为接口应该旨在使使用错误成为不可能。

对于这个问题的任何帮助,我将不胜感激。

问题的原始陈述以及关于可能解决方案的想法如下。

编辑2:

现在有一个赏金这个问题。解决方案必须满足以下要求:

  1. 当且仅当没有对它的引用时才释放该资源。
  2. 对资源的引用可能会被显式销毁。如果在释放资源时发生错误,则会引发异常。
  3. 不能使用已经释放的资源。
  4. 资源的引用计数和释放是线程安全的

解决方案满足以下要求:

  1. 它使用boost提供的共享指针、C++ Technical Report 1 (TR1)和即将推出的 C++ 标准C++0x
  2. 它是通用的。资源类只需要实现资源的释放方式即可。

感谢您的时间和想法。

编辑 3:

感谢所有回答我问题的人。

Alsk 的回答满足了赏金中的所有要求,并被接受。在多线程代码中,此解决方案将需要一个单独的清理线程。

我添加了另一个答案,其中清理期间的任何异常都由实际使用资源的线程引发,而无需单独的清理线程。如果您仍然对这个问题感兴趣(它困扰了我很多),请发表评论。

智能指针是安全管理资源的有用工具。此类资源的示例是内存、磁盘文件、数据库连接或网络连接。

在典型的场景中,封装资源的类应该是不可复制的和多态的。支持这一点的一个好方法是提供一个返回共享指针的工厂方法,并将所有构造函数声明为非公共的。共享指针现在可以自由复制和分配。当没有对它的引用时,该对象将自动销毁,然后析构函数释放资源。

但是这种方法存在一个问题。析构函数不能抛出,因此释放资源的失败将不会被检测到。

解决这个问题的一个常见方法是添加一个公共方法来释放资源。

不幸的是,这种方法引入了另一个问题:我们的对象现在可能包含已经释放的资源。这使资源类的实现复杂化。更糟糕的是,它使该类的客户可能错误地使用它。以下示例可能看起来有些牵强,但它是多线程代码中的常见缺陷。

要么我们确保在对象被销毁之前不释放资源,从而失去任何处理失败资源释放的方法。或者我们提供了一种在对象生命周期内显式释放资源的方法,从而可以错误地使用资源类。

有办法摆脱这种困境。但解决方案涉及使用修改后的共享指针类。这些修改可能会引起争议。

典型的共享指针实现,例如 boost::shared_ptr,要求在调用其对象的析构函数时不抛出异常。通常,任何析构函数都不应该抛出,所以这是一个合理的要求。这些实现还允许指定自定义删除函数,当没有对对象的引用时调用该函数以代替析构函数。不抛出要求扩展到此自定义删除器功能。

这个要求的基本原理很清楚:共享指针的析构函数不能抛出。如果删除函数不抛出,共享指针的析构函数也不会抛出。然而,对于导致资源释放的共享指针的其他成员函数也是如此,例如reset():如果资源释放失败,则不会抛出异常。

这里提出的解决方案是允许自定义删除函数抛出。这意味着修改后的共享指针的析构函数必须捕获删除函数抛出的异常。另一方面,除析构函数之外的成员函数,例如reset(),不应捕获删除函数的异常(并且它们的实现变得更加复杂)。

这是原始示例,使用抛出删除器函数:

我们现在可以使用 reset() 显式释放资源。如果在另一个线程或程序的另一部分中仍然存在对该资源的引用,则调用 reset() 只会减少引用计数。如果这是对该资源的最后一次引用,则释放该资源。如果资源释放失败,则会引发异常。

编辑:

这是删除器的完整(但依赖于平台)实现:

0 投票
2 回答
477 浏览

c++ - 非对象类型的 C++ 智能指针?

我正在尝试使用智能指针,例如 auto_ptr、shared_ptr。但是,我不知道如何在这种情况下使用它。

我不确定,但我认为存储变量只是一个 malloc 的内存,而不是 C++ 类对象。有没有办法将智能指针用于存储变量?

谢谢你。

0 投票
3 回答
6219 浏览

c++ - 我可以从 boost 的weak_ptr 中得到一个原始指针吗?

是否可以从 boost::weak_ptr 获取原始指针?Boost 的 shared_ptr 有 get() 方法和“->”操作符。weak_ptr 没有相同的功能背后是否有一些理由?

0 投票
1 回答
1911 浏览

c++ - CComPtr CoCreateInstance 返回 0x80070582(类已存在。)

我有一个当用户按下登录按钮时调用的 StartComObjects 函数和一个当用户按下取消按钮时调用的 StopComObjects 函数。StartComObjects 函数使用 CComPtr.CoCreateInstance 创建 COM 对象并使用 AfxConnectionAdvise 设置一些连接点。当用户按下取消按钮时,连接点使用 AfxConnectionUnadvise 断开连接,COM 对象在调用 CComPtr 上的 Release 之前停止。

当我第二次按下登录按钮时,CComPtr.CoCreateInstance 返回 0x80070582(类已存在)。这可以防止在第二次调用 StartComObjects 时创建 COM 对象。我不确定为什么这不起作用。不应该 CComPtr::Release 释放 COM 对象并允许我在旧对象停止后创建一个新对象吗?有没有办法解决这个问题?

0 投票
3 回答
3052 浏览

c++ - intrusive_ptr:为什么不提供通用基类?

boost::intrusive_ptr需要intrusive_ptr_add_refintrusive_ptr_release被定义。为什么不提供可以做到这一点的基类?这里有一个例子:http: //lists.boost.org/Archives/boost/2004/06/66957.php,但海报说“我不一定认为这是个好主意”。为什么不?

更新:我认为这个类可能与多重继承一起被滥用这一事实是不够的。任何从具有自己的引用计数的多个基类派生的类都会有同样的问题。这些引用计数是否通过基类实现没有区别。

我认为多线程没有任何问题。boost::shared_ptr提供原子引用计数,这个类也可以。

0 投票
4 回答
112622 浏览

c++ - shared_ptr 在哪里?

经过几个小时试图找到 shared_ptr 的位置后,我现在非常沮丧。我看到的所有示例都没有显示包含shared_ptr(和工作)标题的完整代码。简单地说stdtr1根本<memory>没有帮助!我已经下载了提升,但仍然没有出现!有人可以告诉我在哪里可以找到它吗?

谢谢你让我发泄我的不满!

编辑:我看到我的标题已更改。对于那个很抱歉。所以...这也是因为我不清楚 shared_ptr 是否“依赖于 C++ 版本”->这就是我没有说明我的环境的原因->因此可能是为什么我很难找到它。

我正在研究 MSVS2008。

编辑 2:我不知道为什么,但我在到处寻找 shared_ptr 时包括 [memory] ​​和 [boost/tr1/memory.hpp] 和 [boost/tr1/tr1/memory] ​​.. 当然,我不能不。

感谢所有的回复。