我正在阅读 Scott Meyers 的std::shared_ptr
一书中的Effective Modern C++14
。这是一个代码,其中作者说,潜在的资源泄漏可能是:
int computePriority(); // this function always throw an exception
// ...
processWidget(std::shared_ptr<Widget>(new Widget), // (S.M): potentital
computePriority()); // resource
// leak
Scott Meyers 表示可以在computePriority()
和new Widget
之间调用std::shared_ptr<Widget>(expr)
函数来评估将导致由{{1引起的内存泄漏的内容}}。不应该有一个序列点可以保证new
表达式是否被评估,然后将评估new Widget
?我想到这一点是因为在我看来这是正确的:序列点在std::shared_ptr<Widget>(expr)
中将在没有排序的情况下评估所有它的参数(子表达式)并使共享指针准备就绪,然后做其他事情(无需排序即可评估其他参数)。如果这是不真实的,std::shared_ptr<Widget>(expr)
是正确的(我仍然相信他,显然)
,这种行为会不正确?
是否有规则可以解释为什么这可能?我不擅长序列点,但告诉我他们的人说这应该是有效的。
答案 0 :(得分:4)
排序并不意味着即时性 (在我上班之前,我的醒来是有序的,即使我穿好衣服并在中间吃早餐。)
参数的评估不是相互排序的。
也不是一个参数必须在另一个参数之前完全评估,而不管顺序如何。
也就是说,在shared_ptr构造函数之前对分配进行了排序,但是这些分配都没有针对另一个参数进行排序,并且不能保证分配和构造函数调用之间没有任何反应。
答案 1 :(得分:2)
不应该有一个序列点可以保证
new Widget
表达式是否被评估,然后将评估std::shared_ptr<Widget>(expr)
?
不,事实并非如此。 new Widget
和shared_ptr
构造之间没有序列点。
见Sequence point。 (这是C ++ 11 BTW中过时的术语,但逻辑几乎保持不变。)
序列点出现了......
在评估
&&
(逻辑AND
),||
(逻辑OR
)的左右操作数之间....评估三元的第一个操作数&#34;问号&#34;运算符和第二个或第三个操作数。 ....
在完整表达结束时....
在函数调用中输入函数之前....
在函数返回....
初始化程序结束时; ....
每个声明者序列中的每个声明符之间....
- 醇>
8.与输入/输出转换格式说明符关联的操作之后。 ....
答案 2 :(得分:1)
不应该有一个序列点可以保证如果评估新的Widget表达式,那么接下来会评估std :: shared_ptr(expr)吗?
嗯,是的。分号很好,因为它标志着完整表达式的结束。
auto ptr = new Widget; // may throw bad_alloc
std::shared_ptr<Widget> shared(ptr); // may throw bad_alloc
processWidget(std::move(shared), computePriority()); // computePriority may throw
这种方法的一个好处(将共享ptr的构造与new
分开)是这样的构造函数保证删除在异常时传递给它的指针。
但是,如果可以的话,最好避免使用new
,因为它可以更有效地分配(单个连续分配中的控制块和数据块),如果可以的话抛出异常,最终结果是函数没有效果(并且没有内存泄漏)
如果必须
,请选择以下语法std::make_shared
因为两个函数调用从不交错,processWidget(std::make_shared<Widget>(), computePriority());
可能会在computePriority()
之前调用,反之亦然,如果抛出则没有内存泄漏。但是,使用make_shared
块来围绕投掷调用可能符合您的利益,而不是通过内联来实现硬崩溃。
答案 3 :(得分:0)
请参阅http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr以获取参考
只要构造函数不会抛出bad_alloc,在构造函数中使用 Just a bunch of text here, at
the end. yedyedyed
就可以了。
new A
没有此问题(请参阅std::shared_ptr initialization: make_shared<Foo>() vs shared_ptr<T>(new Foo))