在cppref中,以下内容一直保持到C++17:
如果在
f(std::shared_ptr<int>(new int(42)), g())之后调用g并抛出异常,那么像new int(42)这样的代码可能会导致内存泄漏,而f(std::make_shared<int>(42), g())是安全的,因为两个函数调用从不交织。
我想知道C++17中引入的哪些更改使这一点不再适用。
发布于 2018-02-17 17:43:50
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()的副作用之后,甚至没有内存分配。无论是哪种情况,无论如何都不会再次发生内存泄漏。
发布于 2018-02-17 14:43:58
P0145R3文件( 被接受转换为C++17)细化了几个C++构造的计算顺序,包括
后缀表达式从左到右计算。这包括函数调用和成员选择表达式。
具体而言,该文件在标准5.2.2/4段中增加了以下案文:
后缀表达式在表达式列表和任何默认参数中的每个表达式之前进行排序。与参数初始化相关的每一值计算和副作用以及初始化本身在每次值计算之前以及与任何后续参数的初始化相关的副作用之前进行排序。
https://stackoverflow.com/questions/48842397
复制相似问题