给出这个最小的例子:
#include <iostream>
#include <stdexcept>
using std::cout;
using std::endl;
using std::runtime_error;
struct MyObj
{
MyObj() { cout << "constructed\n";}
MyObj(const MyObj& r) { cout << "copied\n"; }
MyObj(MyObj&& r) noexcept { throw runtime_error("I should terminate the program if uncaught"); }// = delete;
};
void Test(MyObj value)
{
cout << "called\n";
}
int main()
{
Test(MyObj());
return 0;
}
在这里,我(认为)实现了所有的构造函数,这些构造函数如果不存在的话,将由编译器实现。我也确认我可以让每个人执行给定的传统调用。我感到困惑的基础在于main
的行为。
Test
要求将传递给它的任何表达式(一旦求值)都可以用于构造MyObj
的离散且独立的值。我通过了以前不存在的默认构造,应该产生一个r值引用&&
。
尝试从&&
构造值是与已实现的move构造函数的完美匹配。 实际上,如果我声明构造函数已删除(= delete;
),则编译器将失败,表示已删除引用的函数,表明我的推理至少在一定程度上是正确的。
但是,当我以代码示例中的代码声明该函数时,该实现注定要在执行时终止该程序...什么都不会发生。最初,我尝试使用cout
来镜像其他构造函数,但没有任何反应,因此我在事前添加了runtime_error
或anti。不过,编译器会警告声明为noexcept
的函数肯定会抛出一个函数,但仍会编译并运行,并打印:
constructed
called
我还有两个问题。
为什么编译器为什么会失败,声称我引用了一个已删除的函数,如果该可执行文件显然不会调用它(在=delete;
情况下)?
如果Test
中的参数值既不通过复制也不移动,那么如何从r值引用中初始化?
注意:这是VS2017托管的MSVC 14.11.25503。
编辑:在给定noexcept
的情况下,我只想澄清一下throw
应该终止程序。