C++ 在C+;中抛出异常时是否使用移动语义+;11?

C++ 在C+;中抛出异常时是否使用移动语义+;11?,c++,c++11,move-semantics,C++,C++11,Move Semantics,在本文中,Herb Sutter解释说,抛出异常需要异常的副本,因为它是作为临时创建的,因此使用std::auto_ptr来规避复制开销。鉴于C++11中提供了移动语义,这仍然是必要的吗?我刚刚检查过,标准允许 忽略将由抛出表达式的操作数指定的对象复制或移动到异常对象中 如果您不改变程序的含义(即如果您要重新播放,并且后续的捕获会突然看到一个已更改的异常对象被前一个catch块更改),则忽略将异常对象复制或移动到与异常对象类型相同的catch子句变量中 由于这些遗漏是允许的,规范要求首先将复


在本文中,Herb Sutter解释说,抛出异常需要异常的副本,因为它是作为临时创建的,因此使用
std::auto_ptr
来规避复制开销。鉴于C++11中提供了移动语义,这仍然是必要的吗?

我刚刚检查过,标准允许

  • 忽略将由抛出表达式的操作数指定的对象复制或移动到异常对象中
  • 如果您不改变程序的含义(即如果您要重新播放,并且后续的捕获会突然看到一个已更改的异常对象被前一个catch块更改),则忽略将异常对象复制或移动到与异常对象类型相同的catch子句变量中
由于这些遗漏是允许的,规范要求首先将复制或移动的源视为右值。因此,这意味着,如果可能,将移动相应的对象。当然,复制和移动省略仍然可以作为首选


更新 我被告知,将catch子句参数的异常对象初始值设定项视为右值初始值设定项的考虑可能会从标准中删除(因为一般来说,在忽略复制/移动时,不可能在所有情况下都检测到程序的行为是否保持不变),因此我建议不要依赖于此(上面第二个项目符号)


您仍然可以依赖的是将局部变量移动到异常对象中,如
throw x;
(上面的第一个项目符号)。

现在不强制从异常对象移动


这是C++11的一个缺陷。请参见。

  • 在抛出表达式时,始终需要创建异常对象的副本,因为原始对象在堆栈展开过程中超出了范围。
  • 在初始化过程中,我们可能期望复制省略(请参见此)–忽略复制或移动构造函数(对象直接构造成目标对象的存储).< /LI>
  • 但即使复制删除可能应用也可能不适用,但应该提供适当的复制构造函数和/或移动构造函数,这是C++标准授权的(见15.1)。请参阅下面的编译错误以供参考。
<> > >但现代C++提供了更多的特性:“移动安全与移动语义和异常”<强> < /P>
struct演示
{
demo()=默认值;

演示(常量演示&){这个副本通常会被一个好的编译器优化掉。你可以通过在副本构造函数上设置一个调试器断点来检查你的副本。异常性能不应该是你关心的问题。如果是,请更正你的程序,使其不是。同意,这更具学术性。它允许抛出仅移动的类型。如果需要可复制性,你不能通过例如,MSVC++2013至少不会调用移动构造函数来抛出std::move(ex)
:当您说“将移动相应的对象”时你的意思是“必须”还是“可能”?我演示了VisualC++ 2012不移动对象,而是调用复制构造函数。这是标准的缺陷吗?@卡斯滕:根据我的理解,我倾向于这是一个bug。
struct demo
{
    demo() = default;
    demo(const demo &) { cout << "Copying\n"; }
    // Exception safe move constructor
    demo(demo &&) noexcept { cout << "Moving\n"; }
private:
    std::vector<int>    m_v;
};
int main()
{
    demo obj1;
    if (noexcept(demo(std::declval<demo>()))){  // if moving safe
        demo obj2(std::move(obj1));             // then move it
    }
    else{
        demo obj2(obj1);                        // otherwise copy it
    }
    demo obj3(std::move_if_noexcept(obj1));     // Alternatively you can do this----------------
    return 0;
}