C++ func(shared_ptr(…)、shared_ptr(…)在什么平台上真正危险?

C++ func(shared_ptr(…)、shared_ptr(…)在什么平台上真正危险?,c++,constructor,shared-ptr,operator-precedence,C++,Constructor,Shared Ptr,Operator Precedence,我记得斯科特·迈尔斯教我的 func(shared_ptr(new P), shared_ptr(new Q)); 是危险的,因为(如果我没记错的话)内存分配、引用计数(构造)和函数参数赋值的顺序允许在极少数情况下出现(理论上?)。为防止出现这种情况,应将共享的\u ptr封装在函数调用中,例如在make\u shared()中 func(make_shared(),make_shared()); 这里也有一些 我想知道在某些系统上,是否有(当前)编译器在某些错误情况下确实会留下一些漏洞?或

我记得斯科特·迈尔斯教我的

func(shared_ptr(new P), shared_ptr(new Q));
是危险的,因为(如果我没记错的话)内存分配、引用计数(构造)和函数参数赋值的顺序允许在极少数情况下出现(理论上?)。为防止出现这种情况,应将
共享的\u ptr
封装在函数调用中,例如在
make\u shared()

func(make_shared

(),make_shared());

这里也有一些

我想知道在某些系统上,是否有(当前)编译器在某些错误情况下确实会留下一些漏洞?或者这些时代已经过去了,或者只是理论上的

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

  • 在Linux i386、x64、ARM、m68k或任何Windows上的g++4.x或g++2.95
  • I368、X64或ARM
  • 的Visual C++
  • Linux或其任何平台上的Clang/LLVM
  • 从Sun或IBM、HPUX、上的C++编译器如何?

是否有人在其特定平台上观察到这种行为?

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

内存泄漏问题由以下两方面引起:

  • 使用
    new
    分配内存可能会抛出
    bad\u alloc
  • 未指定函数参数的求值顺序
boost::shared\u ptr
的文档很好地捕获了它

对一般问题有更详细的处理

它之所以“罕见”,是因为它确实不是很常见的
错误分配
,但是如果要避免内存泄漏,您的代码必须安全地处理这种可能性


(我说“可能”会表现出来——我没有检查它们是否都抛出了
bad\u-alloc
,如果
new
失败…

因为这两个
new
操作都将首先完成,然后它们被传递到
shared\u-ptr
的构造函数中,但是哪些
shared\u-ptr
先构造的是未指定的。),因此,新创建的对象之一可能会导致内存泄漏

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

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

  • 新Q
  • 新P
  • 围绕分配的P构建共享的ptr
  • 围绕分配的Q构建共享的ptr
  • 呼叫func
  • (编译器可以按任意顺序执行1、2、3和4,只要1在4之前,2在3之前)

    按照上面的顺序,如果
    p
    的构造函数或对
    new
    的调用抛出,
    Q
    是内存泄漏(内存已分配,但尚未围绕它构建
    共享的ptr

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

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


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

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


    显然,优化器只能在未指定B和A的相对顺序的情况下重新排列它们,这里正好是这种情况。

    不仅
    new
    bad\u alloc
    是有问题的,而且构造函数
    p()
    Q()
    中抛出的任何异常都是有问题的,对吗?所以,根据函数参数的实现求值顺序,我会在这两种情况下观察内存泄漏,总是吗?这意味着函数参数的“非特定性”与此无关——它可以被指定为,比如说,从左到右,然后我仍然会观察到泄漏。我不会吗?我似乎记得这是alloc/new/param的“非特定性”,我想知道“正确的顺序”是否可以解决它。你的回答很好,但离题了。OP已经意识到了这个问题,并询问它是在哪些编译器/平台上被目击的。@towi-你说得对-在构建任何一个编译器/平台的过程中,任何异常都可能引发它。未指定的评估顺序意味着兼容实现可以按照它喜欢的任何顺序对它们进行评估,只要它们在输入函数体时全部/完全/评估。将此绑定到一个指定的顺序将删除一个重要的优化点,并可能使某些平台很难实现它。这听起来是事实。这总是“事情的顺序”吗?或者只有“一个可能的顺序”,而另一个顺序可以防止这种泄漏吗?@towi有许多不同的顺序,并且哪个顺序将取决于编译器、用于调用它的选项以及周围的上下文(有多少寄存器可用,等等)。你所能说的是,大多数(如果不是所有的话)编译器在某些情况下都会使用一个中断第一行的顺序。一个编译器是否符合实现顺序1、4、2、3、5的标准,这能解决问题吗?首先,做所有的
    Q
    -工作,然后做所有的
    P
    -工作?是的,这是兼容的,但是编译器不知道什么是共享的\u ptr(类除外)。它不知道它应该先创建智能指针。@utnapistim:OP知道这个问题,问题是它是否是理论上的,或者某些编译器是否表现出这种行为(以及哪些)。@SteveL:我也喜欢标准合规性,但是OP没有问标准是否允许它(他知道它允许),但他问道
    func(shared_ptr(new P), shared_ptr(new Q));