4

我记得斯科特·迈耶斯教过我

func(shared_ptr(new P), shared_ptr(new Q));

很危险,因为(如果我没记错的话)内存分配、引用计数(构造)和函数参数分配的顺序允许泄漏理论上少数情况下出现。为了防止这种情况,应该将 in 封装在一个函数调用中,例如 in 。 shared_ptrmake_shared()

func(make_shared<P>(), make_shared<Q>());

这里也有一些关于它的讨论

我想知道该领域是否有(当前)编译器,在某些系统上确实可能在某些错误情况下留下一些漏洞?或者那些时代已经过去了,或者它们只是理论上的,无论如何?

最有趣的是知道这些是否有这个问题:

  • g++ 4.x 或 g++ 2.95,在 Linux i386、x64、ARM、m68k 或任何 Windows 上
  • i368、x64 或 ARM 上的 Visual C++
  • Linux 或其任何平台上的 Clang/LLVM
  • Sun 或 IBM、HP-UX 上的 C++ 编译器怎么样?

有没有人在他的特定平台上观察到这种行为?

4

4 回答 4

4

这不是平台问题,而是异常安全问题。因此,您实际问题的答案是:所有这些平台都可能出现问题。

内存泄漏问题是由于两件事引起的:

  • new使用可能抛出分配内存bad_alloc
  • 评估函数参数的顺序是未指定的。

在这里boost::shared_ptr很好地捕捉它的文档

这里对一般问题有更详细的处理(GOTW)

它可能“罕见”的原因是因为它确实并不常见bad_alloc,但是如果要避免内存泄漏,您的代码必须安全地处理这种可能性。

(我说“可能”展示它——我没有检查过bad_alloc如果new失败它们都会抛出......)

于 2013-08-06T08:36:02.580 回答
0

因为这两个new操作都将先完成,然后将它们传递给shared_ptr的构造函数,但未指定先构造哪个shared_ptr构造,因此其中一个新创建的对象可能会导致内存泄漏。

于 2013-08-06T08:51:51.743 回答
0
func(shared_ptr(new P), shared_ptr(new Q));

C++ 编译器可以按以下顺序自由地实现它:

  1. 新Q
  2. 新P
  3. 围绕分配的 P 构造 shared_ptr
  4. 围绕分配的 Q 构造 shared_ptr
  5. 调用函数

(编译器可以按任意顺序执行 1、2、3 和 4,只要 1 在 4 之前且 2 在 3 之前)。

在上面的顺序中, ifP的构造函数或对newthrows的调用Q是内存泄漏(内存已分配但shared_ptr尚未围绕它构造)。

因此,您应该调用std::make_shared(它优雅地处理分配异常),并且您知道当std::make_shared其中一个返回时,它shared_ptr是完全构造的并且不会泄漏。

我想知道该领域是否有(当前)编译器,在某些系统上确实可能在某些错误情况下留下一些漏洞?

所有符合标准的编译器都会有这种行为。

于 2013-08-06T08:59:49.677 回答
0

如果该优化器执行以下优化,这在任何具有重新排序优化器的平台上都是不安全的A;B;A;B => A;A;B;B。这种优化提高了代码缓存效率,所以总的来说这是一个好主意。

显然,如果 B 和 A 的相对顺序未指定,优化器只能重新排列 B 和 A,这恰好是这里的情况。

于 2013-08-06T11:27:11.263 回答