【发布时间】:2015-09-24 10:48:09
【问题描述】:
我有一个变量,它累积当前异常并且需要在当前异常被抛出时被清理(这样就不会再次报告相同的错误)。问题是throw std::move(ex); 没有调用移动构造函数(这将清除ex),而是调用了一个复制构造函数(这样ex 也会保留已经抛出的错误)。一个 MVCE 如下:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class ThrowMoveTest : exception
{
public:
ThrowMoveTest(const string& what)
{
_what = what;
}
ThrowMoveTest(const ThrowMoveTest& fellow)
{
cout << "Copy " << what() << endl;
_what = fellow._what;
}
ThrowMoveTest(ThrowMoveTest&& fellow)
{
cout << "Move " << what() << endl;
_what = std::move(fellow._what);
}
virtual const char* what() const override
{
return _what.c_str();
}
private:
mutable string _what;
};
int main()
{
try
{
ThrowMoveTest tmt1("Test1");
throw move(tmt1);
}
catch (const ThrowMoveTest& ex)
{
cout << "Caught " << ex.what() << endl;
}
return 0;
}
我正在使用 MSVC++2013 更新 5。
是否有什么我做错了,因此移动构造函数没有被调用?是否可以抛出异常,以便 C++ 中用于异常存储的临时对象被移动构造,而不是从原始对象复制构造?
我尽量避免的是双重复制:构造tmt1 的副本,然后清理原件,然后在throw 语句中使用该副本,这将构造另一个副本用于临时存储。
编辑:上面的代码示例在 MSVC++2013 Update 5 上给出了以下输出
Copy
Caught Test1
虽然预期的输出是
Move
Caught Test1
EDIT2:提交了编译器错误报告https://connect.microsoft.com/VisualStudio/feedback/details/1829824
【问题讨论】:
-
在 Clang 上它会打印“Move”然后是“Caught Test1”。这是您期望的行为吗?顺便说一句,Clang 让我将
noexcept添加到what()覆盖。 -
@JohnZwinck,是的,这是预期的输出,谢谢!所以问题似乎在于 MSVC++2013 不符合标准,对吧?
标签: c++ c++11 exception move-semantics move-constructor