假设您拥有通常永远不会失败的功能,例如:
std::string convert_integer_to_string(int x);
Run Code Online (Sandbox Code Playgroud)
在市政当局,这将是一个候选人noexcept.但是,实现最有可能涉及动态内存管理,因此在为运算符分配内存时,它总是会抛出std :: bad_allocnew.
是否建议将该函数注释为noexcept?
从实际的角度来看,以合理的方式处理内存不足的情况是极其困难的.大多数程序只假设有足够的可用内存.std::terminate正如在某个noexcept函数抛出时所发生的那样,调用std::bad_alloc在这种情况下似乎是合理的.
对我来说noexcept是某种形式的文档.这是一个承诺,你(或优化器)可以安全地假设这个函数永远不会抛出.如果您正在编写一个不关心内存不足情况的应用程序,那么它仍然是一个有效的假设.
我想最安全的建议是noexcept如果std::bad_alloc抛出异常就永远不要使用.另一方面,我想知道是否有优势可以使用noexcept,假设您不关心内存不足的情况(即,如果std::terminate可以).
以下结构无法在C++ 11下编译,因为我已将移动赋值运算符声明为noexcept:
struct foo
{
std::vector<int> data;
foo& operator=(foo&&) noexcept = default;
};
Run Code Online (Sandbox Code Playgroud)
编译器生成的默认移动赋值运算符是noexcept(false)由于std::vector<int>移动赋值也是如此noexcept(false).这反过来是由于默认分配器已std::allocator_traits<T>:: propagate_on_container_move_assignment设置为std::false_type.另见这个问题.
我的问题是,有没有办法强制noexcept使用默认的移动赋值赋值运算符而不必自己定义它?
如果这是不可能的,是有办法,我可以欺骗std::vector<int>应运而生noexcept举动分配,以便noexcept(true)通过传递给我的结构?
我想创建一个像这样的函数指针:
void(*function_pointer)()noexcept;
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用.似乎函数声明中的异常说明符无效.必须有办法做到这一点.对?
这与一个与此不同的问题有关.在这里,我问如何使用noexcept说明符创建一个函数指针.在"函数typedef中的noexcept说明符"这个问题中没有被问到或回答过.
这段代码编译并运行,抛出int:
#include <functional>
void r( std::function<void() noexcept> f ) { f(); }
void foo() { throw 1; }
int main()
{
r(foo);
}
Run Code Online (Sandbox Code Playgroud)
但是我希望编译器拒绝该行,r(foo);因为r只应传递一个noexcept函数.该noexcept说明符似乎被忽略.有没有办法实现这一目标?
编辑:这个问题是不同的是关于传递函数指针时应该转发的noexcept-ness的知识?因为我要求补救,特别是在这种情况下std::function.
假设我有一个包装类型
template <typename T>
struct X {/*..*/};
Run Code Online (Sandbox Code Playgroud)
我不能X(X&&) = default因为我必须在那里做非平凡的事情.
不过,我希望它是noexcept,但只有在这种情况下T(T&&)是noexcept.这可以测试::std::is_nothrow_move_constructible.
我不知道如何有条件地启用一个版本的构造函数或另一个版本取决于a constexpr.我想可能有办法使用SFINAE,但我不知道如何将它应用于ctors.
我有一个与此问题非常相似的问题.
简而言之,我有一个magic方法,noexcept如果是另一种方法noexcept.
奇怪的是,这个"另一个方法"有两个重载,编译器选择第二个重载来确定magic noexcept-ness.
但是,当magic稍后调用时,会调用第一个重载,但是noexcept-ness magic仍然保持不变!
这是wandbox 链接
据我所知:
noexcept(magic(dummy2{})) 电话noexcept(noexcept(adl_caller(...)) 这可以追溯到adl_caller(..., priority_tag<0>) noexcept因为user_method(dummy2)此时编译器不知道.然而,相当公平,如何user_method(dummy2)称为3行以上?这是标准的意图吗?
对不起,如果我不够清楚的话.
#include <iostream>
template <unsigned N> struct priority_tag : priority_tag<N - 1> {};
template <> struct priority_tag<0> {};
template <typename T>
auto adl_caller(T t, priority_tag<1>) noexcept(noexcept(user_method(t)))
-> decltype(user_method(t)) {
std::cout << "first adl_caller overload" << std::endl;
user_method(t);
}
// …Run Code Online (Sandbox Code Playgroud) 在为我的爱好操作系统实现一个基本的std库时,我遇到了这个并想知道为什么:
双方operator->()并T* get()标记为noexcept,但operator*()并非如此.根据参考,它应该相当于*get(),它将允许它noexcept并且看一些实现我认为没有理由不是.
为什么unique_ptr解除引用运算符没有标记为noexcept?
请考虑以下代码段:
版本(1)
void q() {}
class B {
void f() noexcept(noexcept(q())) {q(); }
decltype(&B::f) f2;
};
Run Code Online (Sandbox Code Playgroud)
版本(2)
void q() {}
class B {
void f() noexcept(true) {q(); }
decltype(&B::f) f2;
};
Run Code Online (Sandbox Code Playgroud)
版本(3)
void q() {}
class B {
void f() noexcept {q(); }
decltype(&B::f) f2;
};
Run Code Online (Sandbox Code Playgroud)
所有版本的GCC都会编译这些代码片段而不会出现任何错误或警告(包括trunk-version).支持C++ 17的所有版本的Clang拒绝版本(1)和(2),但不支持版本(3),并出现以下错误:
<source>:4:16: error: exception specification is not available until end of class definition
decltype(&B::f) f2;
^
Run Code Online (Sandbox Code Playgroud)
考虑到标准定义noexcept为等同于noexcept(true)[except.spec].因此,版本(2)和版本(3)应该是等价的,它们不适用于clang.
因此,以下问题:在什么时候需要根据C++ 17标准评估异常规范?并且,如果上面的某些代码无效,背后的理性是什么?
感兴趣的人的抽象背景:
template <typename F>
struct result_type;
template<typename R, typename C, …Run Code Online (Sandbox Code Playgroud) 请参阅以下代码:
#include <utility>
struct A {
A(int, int) {}
};
struct tag {};
template <class... Args>
struct is_noexcept {
static constexpr bool value = noexcept(A{std::declval<Args>()...});
};
struct B : A {
//#1
template <class... Args>
B(tag, Args&&... args) noexcept(/*Here*/is_noexcept<Args...>::value) :
A{std::forward<Args>(args)...} {}
//#2
B(int x, int y) : A{x, y} {}
};
int main()
{
B x{0, 0};
}
Run Code Online (Sandbox Code Playgroud)
这段代码似乎被GCC/Clang接受,但MSVC 2017拒绝接受.似乎MSVC编译器试图理解是#1不是适当的过载(由于之间的不相容之前计算noexcept符tag和int),因此应被丢弃.因此,它试图评估is_noexcept<int>::value并发现noexcept(A{std::declval<int>()})是不正确的.由于这不是在紧急情况下发生的,因此这不是SFINAE的用武之地,所以很难发生错误.
(其实,我不是很肯定这一点,但我已经证实,如果我把noexcept(A{std::declval<Args>()...}),而不是is_noexcept<Args...>::value在/*Here*/做直接的上下文中发生故障时,MSVC编译器愉快地下降#1和#调用2.这是正确的? )
我怀疑GCC/Clang是对的,MSVC是错的,但哪一个是正确的?
C++ 17补充说std::uninitialized_move,但没有内部std::uninitialized_move_if_noexcept使用std::move_if_noexcept.在我看来,这将是有用的,因为现在,如果我们想要重新分配,我们仍然需要写一些东西
if constexpr (!std::is_nothrow_move_constructible_v<value_type>
&& std::is_copy_constructible_v<value_type>)
std::uninitialized_copy(...);
else
std::uninitialized_move(...);
Run Code Online (Sandbox Code Playgroud)
有没有特别的原因为什么std::uninitialized_move_if_noexcept没有在C++ 17中引入?
c++ ×10
noexcept ×10
c++11 ×5
c++17 ×2
bad-alloc ×1
dereference ×1
function ×1
move ×1
templates ×1
unique-ptr ×1