在什么平台上func(shared_ptr(...),shared_ptr(...))真的很危险?

时间:2013-08-06 08:26:46

标签: c++ constructor shared-ptr operator-precedence

我记得Scott Meyers教会我

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

很危险,因为(如果我没记错的话)内存分配顺序引用计数(构建)和的赋值>函数参数 允许leak (理论上?)在极少数情况下出现。为防止这种情况,应将shared_ptr封装在函数调用中,例如在make_shared()

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

以下是关于它的一些discussion

我想知道某些系统中是否存在(当前)编译器 ,在某些错误情况下确实可能会留下一些漏洞?或者那些时代已经消失,还是只是理论上的呢?

最有趣的是,如果其中任何一个都有这个问题:

  • 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 个答案:

答案 0 :(得分:4)

这不是平台问题,而是一个例外安全问题。因此,您实际问题的答案是:所有这些平台可能会出现问题。

由于两件事情而引起内存泄漏问题:

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

boost::shared_ptr的文档可以很好地捕获here

对一般问题here (GOTW)

进行了更详细的处理

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

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

答案 1 :(得分:0)

因为两个new操作都将首先完成,然后它们被传递到shared_ptr的构造函数中,但是shared_ptr构造首先是未指定的,所以新创建的对象之一可能会导致内存泄漏。

答案 2 :(得分:0)

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

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

  1. new Q
  2. new P
  3. 围绕分配的P
  4. 构建shared_ptr
  5. 围绕分配的Q
  6. 构建shared_ptr
  7. call func
  8. (编译器可以按任意顺序执行1,2,3和4,只要1在4之前,2在3之前)。

    按照上面的顺序,如果P的构造函数或对new的调用抛出,Q是内存泄漏(内存已分配,但shared_ptr不是然而围绕它建造。)

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

      

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

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

答案 3 :(得分:0)

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

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