其他分享
首页 > 其他分享> > c-引发异常时不调用Move构造函数

c-引发异常时不调用Move构造函数

作者:互联网

我有一个变量,它会累积当前异常,并且在抛出当前异常时需要清除该变量(这样就不会再次报告相同的错误).问题是抛出std :: move(ex);不调用move构造函数(这将清除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 Update 5.

我在做错什么事,因此不因此而调用move构造函数吗?是否有引发异常的方法,以便在C中用于异常存储的临时对象是移动构造的,而不是从原始副本构造的?

我要避免的是双重复制:构造tmt1的副本,然后清洗原始副本,然后使用copy in throw语句,这将构造另一个副本用于临时存储.

编辑:上面的代码示例在MSVC 2013 Update 5上提供以下输出

Copy
Caught Test1

虽然预期的输出是

Move
Caught Test1

EDIT2:提交了一个编译器错误报告https://connect.microsoft.com/VisualStudio/feedback/details/1829824

解决方法:

这是一个MSVC错误.从[除外]:

Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object.

这意味着我们这样做:

ThrowMoveTest __exception_object = move(tmt1);

绝对应该调用move构造函数.

请注意,此处的移动是不必要的,也会造成破坏. [class.copy]规定可以删除复制/移动构造

— in a throw-expression (5.17), when the operand is the name of a non-volatile automatic object (other than
a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost
enclosing try-block (if there is one), the copy/move operation from the operand to the exception
object (15.1) can be omitted by constructing the automatic object directly into the exception object

因此,只需抛出tmt1;本来可以将tmt1直接构建到异常对象中.尽管gcc和clang都不这样做.

即使不忽略复制/移动,也可以:

When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the
object to be copied is designated by an lvalue […] overload resolution
to select the constructor for the copy is first performed as if the object were designated by an rvalue.

因此抛出tmt1;仍将移动构造异常对象.

标签:move-constructor,c,c11,exception,move-semantics
来源: https://codeday.me/bug/20191011/1895540.html