【问题标题】:Deallocation of memory when argument subexpression of new expression throws当新表达式的参数子表达式抛出时释放内存
【发布时间】:2017-10-10 10:22:08
【问题描述】:

动态分析在我们的代码库中发现了奇怪的内存泄漏。有问题的代码如下所示:

Something *p = new Something(getArgument());

函数getArgument() 有时会抛出的地方。当它抛出时,新分配的对象被泄露。这是由 Visual Studio 2015 (MSC++ 19.0) 编译的。

现在,当我检查规范 (C++14 final draft) 时,第 5.3.4/8 条奇怪地说:

new-expression 可以通过调用 分配函数 (3.7.4.1) 来获取对象的存储空间。如果 new-expression 通过抛出异常终止,它可能通过调用释放函数释放存储 (3.7.4.2)。如果分配的类型是非数组类型,分配函数的名称是operator new 和 释放函数的名称是operator delete。如果分配的类型是数组类型,分配 函数名称为operator new[],释放函数名称为operator delete[]

这里使用“可能”(我在上面突出显示)意味着编译器可以不这样做。

是这样的:

  1. 在规范的其他地方按要求说明,使其成为 Visual C++ 编译器中的一个错误(仅在某些情况下可能发生;没有检查它的一般性),
  2. 规范中的错误,或
  3. 出于某种原因这样写?

注意:当表达式完成时,代码会正确删除对象。没有错误。严格来说,问题在于 new-expression 抛出时会发生什么。

【问题讨论】:

  • 阅读该部分的后续段落。在某些情况下(例如第 10 段),调用分配函数不需要 new 表达式,在这种情况下需要什么。
  • @Peter,嗯,你是对的。

标签: c++ visual-c++ memory-leaks exception-handling language-lawyer


【解决方案1】:

从最新的草稿来看,相关报价在:

expr.new/8: 新表达式 可能 通过调用分配函数为对象获取存储空间 ([basic.stc.dynamic.allocation])。如果新表达式终止于 抛出异常,它可以通过调用 释放函数。 ....

“可能”的使用优先于程序部分:

expr.new/21如果有任何部分 上面描述的对象初始化通过抛出一个终止 异常和一个合适的释放函数可以找到, 调用释放函数来释放对象所在的内存 正在构建,之后异常继续 在新表达式的上下文中传播。如果没有明确 可以找到匹配的释放函数,传播异常 不会导致对象的内存被释放。 [ 注意:这是 当被调用的分配函数不分配时适用 记忆;否则,很可能导致内存泄漏。 —— 尾注 ]


但是您被 C++14 和更早版本中新表达式的不确定顺序所打击;其中说:

$5.3.4/18 分配函数的调用顺序不定 关于 new-initializer 中表达式的求值。 分配对象的初始化在值之前排序 新表达式的计算。未指定是否 如果分配,则评估 new-initializer 中的表达式 函数返回空指针或使用异常退出。

取自 C++14 草案

根据this paper的采用。我们现在在 C++17 中定义了一个序列:

expr.new/19 分配函数的调用顺序在 new-initializer 中表达式的求值。初始化 分配的对象在值计算之前排序 新表达式。



【讨论】:

  • 是的,§5.3.4/19 是 C++17 中的新内容。 C++14(和 MSC++ 19.0 早于 C++17)还没有它。这也意味着该段落是 C++14 中的 §5,3,4/20。
  • 好吧,虽然C++14没有指定,但是分配在此处的表达式之前是排序的,否则显然不会泄漏。
【解决方案2】:

进一步检查 - 特别是第 20 段:

如果上述对象初始化的任何部分因抛出异常而终止并且可以找到合适的释放函数,则调用释放函数以释放构造对象的内存,之后异常继续传播在 new-expression 的上下文中。如果找不到明确匹配的释放函数,则传播异常不会导致对象的内存被释放。 [注:这适用于调用的分配函数不分配内存的情况;否则,很可能导致内存泄漏。 —结束注释]

【讨论】:

    猜你喜欢
    • 2018-02-10
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    • 1970-01-01
    相关资源
    最近更新 更多