std::make_shared() 在 C++17 中的变化
std::make_shared() change in C++17
在 cppref 中,以下内容在 C++17 之前成立:
code such as f(std::shared_ptr<int>(new int(42)), g())
can cause a
memory leak if g
gets called after new int(42)
and throws an
exception, while f(std::make_shared<int>(42), g())
is safe, since
two function calls are never interleaved.
我想知道 C++17 中引入的哪个更改使它不再适用。
C++17 中的 P0145R3 paper (which was accepted) 细化了几个 C++ 构造的计算顺序,包括
Postfix expressions are evaluated from left to right. This includes functions calls and member
selection expressions
具体来说,论文在标准的5.2.2/4段中增加了如下文字:
The postfix-expression is sequenced before each expression in the
expression-list and any default argument. Every value computation and
side effect associated with the initialization of a parameter, and the
initialization itself, is sequenced before every value computation and
side effect associated with the initialization of any subsequent
parameter.
函数参数的求值顺序被P0400R0改变了。
在更改之前,函数参数的计算相对于彼此是无序的。这意味着 g()
的评估可能会插入到 std::shared_ptr<int>(new int(42))
的评估中,这会导致您引用的上下文中描述的情况。
更改后,函数参数的计算顺序不确定,没有交错,这意味着 std::shared_ptr<int>(new int(42))
的所有副作用都发生在 g()
之前或之后。现在考虑 g()
可能抛出的情况。
如果std::shared_ptr<int>(new int(42))
的所有副作用发生在g()
之前,分配的内存将由std::shared_ptr<int>
的析构函数释放。
如果std::shared_ptr<int>(new int(42))
的所有副作用都发生在g()
之后,甚至没有内存分配。
无论哪种情况,无论如何都不会再次发生内存泄漏。
在 cppref 中,以下内容在 C++17 之前成立:
code such as
f(std::shared_ptr<int>(new int(42)), g())
can cause a memory leak ifg
gets called afternew int(42)
and throws an exception, whilef(std::make_shared<int>(42), g())
is safe, since two function calls are never interleaved.
我想知道 C++17 中引入的哪个更改使它不再适用。
C++17 中的 P0145R3 paper (which was accepted) 细化了几个 C++ 构造的计算顺序,包括
Postfix expressions are evaluated from left to right. This includes functions calls and member selection expressions
具体来说,论文在标准的5.2.2/4段中增加了如下文字:
The postfix-expression is sequenced before each expression in the expression-list and any default argument. Every value computation and side effect associated with the initialization of a parameter, and the initialization itself, is sequenced before every value computation and side effect associated with the initialization of any subsequent parameter.
函数参数的求值顺序被P0400R0改变了。
在更改之前,函数参数的计算相对于彼此是无序的。这意味着 g()
的评估可能会插入到 std::shared_ptr<int>(new int(42))
的评估中,这会导致您引用的上下文中描述的情况。
更改后,函数参数的计算顺序不确定,没有交错,这意味着 std::shared_ptr<int>(new int(42))
的所有副作用都发生在 g()
之前或之后。现在考虑 g()
可能抛出的情况。
如果
std::shared_ptr<int>(new int(42))
的所有副作用发生在g()
之前,分配的内存将由std::shared_ptr<int>
的析构函数释放。如果
std::shared_ptr<int>(new int(42))
的所有副作用都发生在g()
之后,甚至没有内存分配。
无论哪种情况,无论如何都不会再次发生内存泄漏。