Effective Modern C++ 中的此项是否仍然是最新的?
Is this item from Effective Modern C++ still up to date?
p.146 of effective modern C++ :
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());
它曾经是不安全的,因为 computePriority 可以在 new Widget
之后但在 std::share_ptr
构造函数之前调用,如果 computePriority
产生异常,动态 allcoated 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());
我读过 this and this 但我仍然不确定,我相信 std::shared_ptr<Wdiget>(new Widget, cusDel)
和 computePriority()
都在调用 processWidget 之前排序,但我认为 computePriority()
仍然可以在 new
之后和 shared_ptr
取得新创建对象的所有权之前抛出异常。
建议而不是直接回答您的问题。
我将应用于这种情况的原则:如果语句的安全性不明显,那么就不要假设它 - 即使 language-lawyering 可以为您找到适当的保证。做出微妙假设的代码通常不是一个好主意。如果有人由于某些兼容性限制而尝试用 C++14 编译它怎么办?他们不会收到警告。
相反,通过使用 two-line 解决方案(使用 std::move)或编写一个 make_shared()
版本,它也采用自定义删除器来省去麻烦 - 可能类似于这个:
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 );
}
然后调用:
processWidget(nonstd::make_shared_with_deleter<Widget>(cusDel), computePriority());
另见关于 的相同论点。
C++17 确实改变了用于调用函数的表达式的计算顺序。虽然它没有强加任何特定顺序,但 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.
“不确定顺序”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.
所以一个参数会先于另一个参数初始化,包括allside-effects。所以第一个参数或第二个参数在另一个之前被完全评估。
p.146 of effective modern C++ :
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());
它曾经是不安全的,因为 computePriority 可以在 new Widget
之后但在 std::share_ptr
构造函数之前调用,如果 computePriority
产生异常,动态 allcoated 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());
我读过 this and this 但我仍然不确定,我相信 std::shared_ptr<Wdiget>(new Widget, cusDel)
和 computePriority()
都在调用 processWidget 之前排序,但我认为 computePriority()
仍然可以在 new
之后和 shared_ptr
取得新创建对象的所有权之前抛出异常。
建议而不是直接回答您的问题。
我将应用于这种情况的原则:如果语句的安全性不明显,那么就不要假设它 - 即使 language-lawyering 可以为您找到适当的保证。做出微妙假设的代码通常不是一个好主意。如果有人由于某些兼容性限制而尝试用 C++14 编译它怎么办?他们不会收到警告。
相反,通过使用 two-line 解决方案(使用 std::move)或编写一个 make_shared()
版本,它也采用自定义删除器来省去麻烦 - 可能类似于这个:
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 );
}
然后调用:
processWidget(nonstd::make_shared_with_deleter<Widget>(cusDel), computePriority());
另见关于
C++17 确实改变了用于调用函数的表达式的计算顺序。虽然它没有强加任何特定顺序,但 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.
“不确定顺序”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.
所以一个参数会先于另一个参数初始化,包括allside-effects。所以第一个参数或第二个参数在另一个之前被完全评估。