是复制构造函数中初始值设定项列表中的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
。
任何帮助都将被感激!
cpp编码指南在E.12中对此非常清楚:当由于抛出而退出函数时使用noexcept是不可能的或不可接受的
因此,您可以使用noexcept
,即使该函数/ctor的调用可能会导致异常,如果您认为该异常会导致应用程序处于不可处理的状态。
指南示例:
vector<double> munge(const vector<double>& v) noexcept { vector<double> v2(v.size()); // ... do something ... }
这里的
noexcept
表示我不愿意或不能处理我不能构造局部向量的情况。也就是说,我认为内存耗尽是一个严重的设计错误(与硬件故障一样),所以如果发生这种情况,我愿意让程序崩溃。
因此,如果Foo
的失败构造可以使用try-catch
块来处理,而不会出现严重问题。那你就不用noexcept
了。
反思其他一些答案:如果函数可能抛出,我不会使用noexcept
,即使你不在乎程序最终是否会终止。因为如果一个声明为noexcept
的函数抛出,它就会抛出。声明函数noexcept
为类的用户保存语义信息,他们可能依赖于这些信息,在您的情况下,这基本上是不真实的。
编辑:我建议你阅读Scott Meyers的《有效的现代C++》第14条,它很好地描述了使用noexcept的好处以及何时使用它。
我认为这实际上取决于上下文。如果您能够合理地处理该异常(并期望它被抛出),那么就不应该将其标记为noexcept
。另一方面,如果您的程序无法从异常中恢复,您不妨将其标记为noexcept
当要分配的对象很小时,第二种情况是正确的(如果不能分配一个char
,则无法进行大量异常处理)。第一个应该发生在真正大的对象上(例如,您可以推迟分配)。话虽如此,如果你正在复制一个巨大的物体。。。为什么不把它移走呢?
简单答案:如果您知道它可能抛出,并且没有充分的理由这样做(例如,如果无法创建副本,您希望应用程序调用std::terminate),则不要声明它为noexcept。
问问自己会有什么收获。当编译器没有异常时,它能优化任何东西吗?我没有看到很多情况会出现这种情况(我看到优化的最常见情况是针对移动,因为std库容器可以使用它——他们检查移动操作是否不例外,这样他们就可以保持保证)。另一个可以使用它的地方是,当您想要记录函数不能抛出的内容时。这里显然不是这样。
另一方面,您将无法再从可能的异常中恢复,您的程序将终止。
所以在夏天,你不会得到任何东西,但你可能会失去一些东西。
还可参考核心指南:
E.12:由于抛出不可能或不可接受而退出函数时使用noexcept
这条规则的标题可能有点令人困惑。它说,如果
- 它不投掷或
- 如果出现异常,你不在乎。您愿意使程序崩溃,因为由于内存耗尽,您无法处理std::bad_alloc等异常
如果您是对象的直接所有者,抛出异常不是一个好主意。
顺便说一句,以下特殊成员函数隐式不例外:
- 默认构造函数
- 析构函数(据我所知,即使你明确地抛出它)
- 移动并复制构造函数
- 移动和复制分配运算符
何时使用noexcept
"最佳实践">
必须考虑是否需要在每个函数声明后附加
noexcept
,这将大大降低程序员的工作效率(坦率地说,这将是一种痛苦)。
那么,当很明显函数永远不会抛出时,就使用它。
使用
noexcept
后,我什么时候才能真正观察到性能改进?[…]就我个人而言,我关心noexcept
,因为它为编译器提供了更大的自由度,可以安全地应用某些类型的优化。
最大的优化收益似乎来自用户优化,而不是编译器优化,因为可能会检查noexcept
并对其进行重载。如果你不使用异常处理方法,大多数编译器都不会受到惩罚,所以我怀疑它会在你的代码的机器代码级别上发生很大变化,尽管可能通过移除处理代码来减小二进制大小。
在big 4中使用noexcept
(构造函数、赋值,而不是析构函数,因为它们已经是noexcept
了)可能会带来最好的改进,因为noexcept
检查在模板代码(如std容器)中是"常见的"。例如,std::vector
不会使用类的move,除非它被标记为noexcept
(或者编译器可以以其他方式推断它)。
- 为什么 std::unique 不调用 std::sort?
- 在noexcept 规范中是否允许使用"this"?
- 使用 noexcept 运算符 depenendet
- NOEXCEPT 函数调用运算符的说明符_Not_fn
- 生成"unique"矩阵
- 参数包内 noexcept 说明符
- 当 noexcept 函数尝试在 gcc 或 clang 中调用非 noexcept 函数时启用警告
- 为什么使用 std::vector 的代码不能编译,但使用 std::unique_ptr 如果没有 noexcept
- 我对 std::unique(算法)C++有问题
- 我如何静态断言static_cast是 noexcept?
- "noexcept-expression 由于对......的调用而计算为'假'"是什么意思?
- 如何为C++函数指定 noexcept ?
- std::shared_ptr::unique(),复制和线程安全
- 如何知道函数何时抛出以及何时使用noexcept
- 如何在C++03中用自定义谓词调用std::unique
- 添加noexcept是否会破坏二进制兼容性
- noexcept未通过衰变去除
- 为什么旧的空抛规范被用新的语法"noexcept"重写?
- 在模板中使用 noexcept 运算符
- 在 vs2012 中,lambda 中的 noexcept 如何工作?