复制构造函数中初始化列表中的 make_unique 是不使用 noexcept 说明符的良好目的吗?
Is make_unique in initializer list in copy constructor good purpose to not use noexcept specifier?
我的复制构造函数旁边有一个 noexcept 说明符的障碍。
#include <memory>
#include <vector>
class Foo final {
public:
Foo() noexcept = default;
Foo(const Foo& oth) : impl_(std::make_unique<Foo::Impl>()) {} // <---
~Foo() noexcept = default;
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
class Foo::Impl {
...
private:
std::vector<int> some_data;
}
我不确定是否应该将 noexcept
放在复制构造函数旁边,而 std::make_unique
可以抛出 bad_alloc
.
我们将不胜感激!
我认为这确实取决于上下文。如果您可以合理地处理该异常(并期望它被抛出),那么您不应该将其标记为 noexcept
。另一方面,如果您的程序无法从异常中恢复,您不妨将其标记为 noexcept
.
当要分配的对象相当小时,我会说第二种情况是正确的(如果不能分配单个 char
,您将无法进行大量异常处理)。
第一个应该发生在非常大的对象上(例如你可以推迟分配)。也就是说,如果您正在复制一个巨大的对象...为什么不移动它呢?
简单回答:不要声明它 noexcept,如果你知道它可能会抛出并且你没有很好的理由这样做(例如你想要你的应用程序如果无法制作副本,请致电 std::terminate。
问问自己会有什么收获。当它是 noexcept 时,编译器可以优化任何东西吗?我没有看到很多情况会出现这种情况(我看到优化的最常见情况是移动,因为标准库容器可以使用它 - 他们检查移动操作是否为 noexcept 以便他们可以保持他们的保证).另一个你可能会用到它的地方是当你想记录一个函数不能抛出的时候。这显然不是这里的情况。
另一方面,您将无法再从可能的异常中恢复,您的程序将终止。
所以在夏天,你不会得到什么,反而可能会失去一些东西。
另请参阅核心指南:
E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable
The title of this rule may be a little bit confusing. It says that you should declare a function as noexcept, if
- it does not throw or
- you don't care in case of an exception. You are willing to crash the program because you can not handle an exception such as std::bad_alloc due to memory exhaustion.
It's not a good idea to throw an exception if you are the direct owner of an object.
顺便说一下,下面的特殊成员函数是隐式的noexcept:
- 默认构造函数
- 析构函数(据我所知,即使你明确地抛出它)
- 移动和复制构造函数
- 移动和复制赋值运算符
什么时候使用noexcept
"best practices"
Having to think about whether or not I need to append noexcept
after every function declaration would greatly reduce programmer productivity (and frankly, would be a pain).
那么当函数显然永远不会抛出时使用它。
When can I realistically expect to observe a performance improvement after using noexcept
? [...] Personally, I care about noexcept
because of the increased freedom provided to the compiler to safely apply certain kinds of optimizations.
似乎最大的优化收益来自用户优化,而不是编译器优化,因为可能会检查 noexcept
并对其进行重载。大多数编译器都遵循“如果你不抛出异常则不会受到惩罚”的异常处理方法,所以我怀疑它会在你的代码的机器代码级别上改变很多(或任何东西),尽管可能通过删除处理来减少二进制大小代码。
在大 4 中使用 noexcept
(构造函数、赋值,而不是析构函数,因为它们已经 noexcept
)可能会带来最好的改进,因为 noexcept
检查是 'common' 在模板代码中,例如在 std 容器中。例如,std::vector
不会使用你的 class 的着法,除非它被标记为 noexcept
(否则编译器可以推断出它)。
cpp 编码指南在 E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable
中对此非常清楚
因此您可以使用 noexcept
,即使 function/ctor 的调用可能导致异常,如果该异常会 - 在您看来 - 导致您的应用程序处于无法处理的状态。
指南中的示例:
vector<double> munge(const vector<double>& v) noexcept
{
vector<double> v2(v.size());
// ... do something ...
}
The noexcept
here states that I am not willing or able to handle the situation where I cannot construct the local vector. That is, I consider memory exhaustion a serious design error (on par with hardware failures) so that I'm willing to crash the program if it happens.
因此,如果 Foo
的构建失败,可以使用 try-catch
块来处理而不会出现严重问题。那么你不会在那里使用noexcept
。
反思其他一些答案:如果函数可能会抛出异常,我不会使用 noexcept
,即使您不关心程序最终是否会终止也是如此。因为它会,如果声明为 noexcept
的函数抛出。
声明您的函数 noexcept
为您的 class 的用户保存语义信息,他们可以依赖此信息,这在您的情况下基本上是不真实的。
编辑:我建议您阅读 Scott Meyers 的 Effective Modern C++ 的第 14 条,它很好地描述了使用 noexcept 的好处以及何时使用它。
我的复制构造函数旁边有一个 noexcept 说明符的障碍。
#include <memory>
#include <vector>
class Foo final {
public:
Foo() noexcept = default;
Foo(const Foo& oth) : impl_(std::make_unique<Foo::Impl>()) {} // <---
~Foo() noexcept = default;
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
class Foo::Impl {
...
private:
std::vector<int> some_data;
}
我不确定是否应该将 noexcept
放在复制构造函数旁边,而 std::make_unique
可以抛出 bad_alloc
.
我们将不胜感激!
我认为这确实取决于上下文。如果您可以合理地处理该异常(并期望它被抛出),那么您不应该将其标记为 noexcept
。另一方面,如果您的程序无法从异常中恢复,您不妨将其标记为 noexcept
.
当要分配的对象相当小时,我会说第二种情况是正确的(如果不能分配单个 char
,您将无法进行大量异常处理)。
第一个应该发生在非常大的对象上(例如你可以推迟分配)。也就是说,如果您正在复制一个巨大的对象...为什么不移动它呢?
简单回答:不要声明它 noexcept,如果你知道它可能会抛出并且你没有很好的理由这样做(例如你想要你的应用程序如果无法制作副本,请致电 std::terminate。
问问自己会有什么收获。当它是 noexcept 时,编译器可以优化任何东西吗?我没有看到很多情况会出现这种情况(我看到优化的最常见情况是移动,因为标准库容器可以使用它 - 他们检查移动操作是否为 noexcept 以便他们可以保持他们的保证).另一个你可能会用到它的地方是当你想记录一个函数不能抛出的时候。这显然不是这里的情况。
另一方面,您将无法再从可能的异常中恢复,您的程序将终止。
所以在夏天,你不会得到什么,反而可能会失去一些东西。
另请参阅核心指南:
E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable
The title of this rule may be a little bit confusing. It says that you should declare a function as noexcept, if
- it does not throw or
- you don't care in case of an exception. You are willing to crash the program because you can not handle an exception such as std::bad_alloc due to memory exhaustion.
It's not a good idea to throw an exception if you are the direct owner of an object.
顺便说一下,下面的特殊成员函数是隐式的noexcept:
- 默认构造函数
- 析构函数(据我所知,即使你明确地抛出它)
- 移动和复制构造函数
- 移动和复制赋值运算符
什么时候使用noexcept
"best practices"
Having to think about whether or not I need to append
noexcept
after every function declaration would greatly reduce programmer productivity (and frankly, would be a pain).
那么当函数显然永远不会抛出时使用它。
When can I realistically expect to observe a performance improvement after using
noexcept
? [...] Personally, I care aboutnoexcept
because of the increased freedom provided to the compiler to safely apply certain kinds of optimizations.
似乎最大的优化收益来自用户优化,而不是编译器优化,因为可能会检查 noexcept
并对其进行重载。大多数编译器都遵循“如果你不抛出异常则不会受到惩罚”的异常处理方法,所以我怀疑它会在你的代码的机器代码级别上改变很多(或任何东西),尽管可能通过删除处理来减少二进制大小代码。
在大 4 中使用 noexcept
(构造函数、赋值,而不是析构函数,因为它们已经 noexcept
)可能会带来最好的改进,因为 noexcept
检查是 'common' 在模板代码中,例如在 std 容器中。例如,std::vector
不会使用你的 class 的着法,除非它被标记为 noexcept
(否则编译器可以推断出它)。
cpp 编码指南在 E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable
中对此非常清楚因此您可以使用 noexcept
,即使 function/ctor 的调用可能导致异常,如果该异常会 - 在您看来 - 导致您的应用程序处于无法处理的状态。
指南中的示例:
vector<double> munge(const vector<double>& v) noexcept { vector<double> v2(v.size()); // ... do something ... }
The
noexcept
here states that I am not willing or able to handle the situation where I cannot construct the local vector. That is, I consider memory exhaustion a serious design error (on par with hardware failures) so that I'm willing to crash the program if it happens.
因此,如果 Foo
的构建失败,可以使用 try-catch
块来处理而不会出现严重问题。那么你不会在那里使用noexcept
。
反思其他一些答案:如果函数可能会抛出异常,我不会使用 noexcept
,即使您不关心程序最终是否会终止也是如此。因为它会,如果声明为 noexcept
的函数抛出。
声明您的函数 noexcept
为您的 class 的用户保存语义信息,他们可以依赖此信息,这在您的情况下基本上是不真实的。
编辑:我建议您阅读 Scott Meyers 的 Effective Modern C++ 的第 14 条,它很好地描述了使用 noexcept 的好处以及何时使用它。