具有按值返回的函数 &noexcept
Function with by-value return & noexcept
这个问题是"带有按值参数的构造函数&noexcept"的对偶问题。这个问题表明,按值函数参数的生存期管理是由调用函数处理的;因此调用方处理发生的任何异常,并且被调用函数可以将自己标记为CCD_ 1。我想知道noexcept
是如何处理输出端的。
MyType MyFunction( SomeType const &x ) noexcept;
//...
void MyCaller()
{
MyType test1 = MyFunction( RandomSomeType() );
MyType test2{ MyFunction( RandomSomeType() ) };
//...
test1 = MyFunction( RandomSomeType() );
test2 = std::move( MyFunction(RandomSomeType()) );
MyFunction( RandomSomeType() ); // return value goes to oblivion
}
假设返回值已在MyFunction
中成功创建。假设MyType
的适当特殊成员函数(复制/移动分配/构造)可能不是noexcept
。
- 关于返回值从被调用函数传递到调用方的RVO/NRVO/Whatever-from-C++11规则是否意味着,无论适当的特殊成员函数的
noexcept
状态如何,传递总是成功无抛出 - 如果上一个问题的答案是"否",那么如果返回值传递抛出,那么异常是针对被调用函数还是调用者计数
- 如果上一个问题的答案是"被调用的函数",那么
MyFunction
上的普通noexcept
标记将导致对std::terminate
的调用。noexcept
0的noexcept
配置文件应该更改为什么?当我在Usenet上问到这件事时,一位受访者认为应该是std::is_nothrow_move_assignable<MyType>::value
。(注意,MyCaller
使用了几种使用返回值的方法,但MyFunction
不知道使用哪一种!答案必须涵盖所有情况。)如果MyType
更改为可复制但不可移动,会有什么不同吗
因此,如果第二个和第三个问题的最坏情况是准确的,那么如果返回类型有可抛出的移动,那么任何按值返回的函数都不可能有普通的noexcept
!现在,具有可抛出移动的类型应该很少见,但每次使用按值返回时,模板代码仍然必须用is_nothrow_move_assignable
"弄脏"自己。
我认为让被调用的函数负责是错误的:
MyType MyFunction( SomeType const &x ) noexcept( ??? )
{
//...
try {
return SOME_EXPRESSION;
// What happens if the creation of SOME_EXPRESSION succeeds, but the
// move-assignment (or whatever) transferring the result fails? Is
// this try/catch triggered? Or is there no place lexically this
// function can block a throwing move!?
} catch (...) {
return MyType();
// Note that even if default-construction doesn't throw, the
// move-assignment may throw (again)! Now what?
}
}
至少在我看来,这个问题在调用者端似乎是可以解决的(只需用try
/catch
包装移动赋值),但在被调用函数端是无法解决的。我认为调用方必须处理这个问题,即使我们需要更改C++的规则。或者至少需要某种缺陷报告。
要回答部分问题,您可以询问某个类型是否是另一个可构造类型:
#include <type_traits>
MyType MyFunction( SomeType const &x )
noexcept(std::is_nothrow_move_constructible<MyType>::value)
{
// ....
}
我认为你的问题很困惑,因为你说的是从被调用者到调用者的"转移",而这不是我们在C++中使用的术语。考虑函数返回值的最简单方法是,被调用者通过"返回槽"(由被调用者构建并由调用者销毁的临时对象)与调用者通信。被调用者负责将返回值构造到"return slot"中,调用者负责将值从"return slow"中取出(如果需要),然后销毁"return slok"中剩余的内容。
MyType MyFunction(SomeType const &x) noexcept
{
return SOME_EXPRESSION;
}
void MyCaller()
{
MyType test1 = MyFunction( RandomSomeType() ); // A
MyType test2{ MyFunction( RandomSomeType() ) }; // B
//...
test1 = MyFunction( RandomSomeType() ); // C
test2 = std::move( MyFunction(RandomSomeType()) ); // D
MyFunction( RandomSomeType() ); // E
}
首先:语句return SOME_EXPRESSION;
导致SOME_EXPRESSION
的结果移动到MyFunction
的"返回槽"中。这一举措可能会被忽略。如果move没有被消除,那么MyType
的move构造函数将被调用。如果move构造函数抛出异常,则可以通过return
本身周围的try块或函数try块捕获异常。
案例A
:在MyFunction
中有一个移动的ctor(可能被忽略),然后将ctor移动到test1
中(可能被消除)。
病例B
:与病例A
相同。
案例C
:在MyFunction
中有一个move ctor(可以省略),然后将赋值移动到test1
中。
病例D
:与病例C
相同。对std::move
的调用没有提供任何好处,而且编写它的风格也不好
案例E
:MyFunction
内部有一个移动ctor(可能被忽略),就这样。
如果在将ctor或移动赋值到test1
的过程中抛出异常,则可以通过将处理test1
的代码封装在try块中来捕获这些异常。MyFunction
内部的代码在这一点上是完全无关的;MyFunction
不知道或不关心调用者将如何处理返回的对象。只有调用者知道,并且只有调用者能够捕获调用者生成的异常。
- NOEXCEPT 函数调用运算符的说明符_Not_fn
- 当 noexcept 函数尝试在 gcc 或 clang 中调用非 noexcept 函数时启用警告
- 如何为C++函数指定 noexcept ?
- 如何知道函数何时抛出以及何时使用noexcept
- `noexcept`函数中的std :: terminate`调用函数有限-GCC vs clang codegen
- 为什么 std::map 的移动构造函数不是 noexcept?
- gmock - 如何使用 noexcept 说明符模拟函数
- 无法专用化函数模板'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept(<expr>)'
- 查找所有移动构造函数和移动赋值运算符(特别是那些没有"noexcept"的运算符)
- 为什么noexcept move构造函数在向量重新分配期间没有被调用
- MSVC 2017中STL容器的移动构造函数未标记为NOExcept
- 在调用C函数的非抛出内联函数上添加noexcept
- 对于具有抛出复制构造函数和noexcept-by-value复制赋值的类,is_nothrow_copy_assigna
- 捕获其中所有异常的C++函数是否"noexcept"?
- std::is_member_function_pointer 不适用于 noexcept 成员函数
- 是复制构造函数中初始值设定项列表中的make_unique不使用noexcept说明符的好用途
- 我应该声明我的异常的副本构造函数noexcept吗
- 默认情况下继承构造函数 noexcept(true)
- 具有按值返回的函数 &noexcept
- 带有按值参数的构造函数 &noexcept