4

有效的现代 C++ 第 146 页:

void processWidget(std::shared_ptr<Widget> spw, int priority);
void cusDel(Widget *ptr);//a custom deleter

这是 C++17 之前的不安全调用:

processWidget(std::shared_ptr<Wdiget>(new Widget, cusDel), computePriority());

它曾经是不安全的,因为可以在构造函数之后new Widget但之前调用computePriority std::share_ptr,如果computePriority产生异常,动态的allcoat Widget 将被泄露。因此你可以这样做:

std::shared_ptr<Widget> spw(new Widget, cusDel);
processWidget(spw, computePriority());

现在这将在 shared_ptr 上添加一个复制构造函数操作。所以你也可以这样做:

std::shared_ptr<Widget> spw(new Widget, cusDel);
processWidget(std::move(spw), computePriority());

所以我的问题是,以下代码是否仍然能够在 C++17 中泄漏内存?

processWidget(std::shared_ptr<Wdiget>(new Widget, cusDel), computePriority());

我已经阅读了这个这个,但我仍然不确定,我相信std::shared_ptr<Wdiget>(new Widget, cusDel)并且computePriority()都在调用 processWidget 之前排序,但是我认为在获得新创建的对象的所有权之后和之前computePriority()仍然可以抛出异常。newshared_ptr

4

2 回答 2

6

C++17 did change the sequencing with regard to the evaluation of the expressions used to call a function. While it doesn't impose any particular order, it does say:

The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter.

"Indeterminately sequenced" is defined as:

Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.

So one parameter will be initialized before the other, including all side-effects. So either the first argument or the second argument is fully evaluated before the other.

于 2020-10-17T13:44:42.397 回答
0

建议而不是直接回答您的问题。

我将适用于这种情况的一个原则:如果陈述的安全性不明显,那么就不要假设它 - 即使语言律师可以为您找到适当的保证。做出微妙假设的代码通常不是一个好主意。如果有人由于某些兼容性限制而尝试使用 C++14 编译它怎么办?他们不会收到警告。

Instead, save yourself the trouble by either using your two-line solution (with std::move), or write a version of make_shared() which also takes the custom deleter - probably something like this:

template< class T, class Deleter, class... Args >
shared_ptr<T> make_shared_with_deleter( Deleter d, Args&&... args )
{
    return std::shared_ptr<T>(new T(std::forward(args)...), d );
}

and then call:

processWidget(nonstd::make_shared_with_deleter<Widget>(cusDel), computePriority());

See also the same argument regarding tuple destruction order.

于 2020-10-17T13:38:35.653 回答