2017-10-12 44 views
4

在C++ 11及更高版本的标准中,是否保证当函数返回一个类对象时调用(可能是异常抛出)拷贝是而不是 - 如果为此类定义了移动ctor?背景:假设C++ 11:通过值返回对象不会在定义移动ctor时抛出异常吗?

struct X { 
    X() {} 
    X(const X&) {/* code that might throw exceptions */} 
    X(X&&) {/* code that never throws exceptions */} 
    ... 
}; 

X my_func(some_type& t) 
{ 
    X x; 
    // code that modifies t and x but never throws exceptions 
    return x; 
} 

现在,确实,例如,这样的表达式

some_other_func(my_func(t)); 

从未抛出异常(?即是此保证)提供的功能some_other_func(const X&)不会抛出异常?那么如果some_other_func的签名是some_other_func(X)呢?

+0

在你的假设情况下,'X'的默认构造函数是否保证不会抛出? –

+0

@ChrisDrew它在上面,它是一个空构造函数。 – Yakk

+0

@Yakk,当然,我想知道是否有什么缺失,因为我很惊讶'X'可以被构造和填充而不会抛出,但不能被丢弃而不被复制。 –

回答

4

规则很简单:函数被视为可以抛出异常,除非它被标记为不能的函数。移动构造函数在这方面与其他任何函数一样。手动定义时,除非定义为noexcept,否则将视为可能投掷。

隐式默认功能(即自动提供的复制&移动操作)通常遵循以下逻辑:声明为noexcept当且仅当它调用的所有函数都是noexcept

+0

我的问题旨在*复制* ctor调用“期间”从一个函数返回的过程中,只要移动ctor可用。当然,上面例子中的举动可能被宣布为noexcept,但这不是我想要引起注意的。 – Teilhart

+0

@Teilhart在*语言*本身,移动ctor与copy ctor的选择从不受异常规范(或缺少异常规范)的驱动。如果移动操作可用,当RHS是右值时将使用ti。否则(不移动op或LHS是左值),将使用复制操作。 *库*像'std :: vector'这样的东西具有更复杂的规则,这是由于异常安全问题。 – Angew

1

例外情况永远不会自发地产生于格式良好的C++程序中,只会执行定义的行为。

如果你的代码是一个格式良好的程序,你永远不会调用或与允许抛出异常的语言或库特性进行交互,并且你编写的代码不会抛出异常(显式地),那么结果就是代码赢了不会抛出异常。

除非您将函数和方法标记为noexcept,否则编译器和标准库可能没有意识到这一点,并可能认为您的代码会抛出异常(即使它不能)。在某些情况下,这可能会导致编译器分配内存并抛出一个异常,因为您的代码可能会抛出异常,或调用其他方法(例如在某些向量操作中复制而不是移动)。

什么你应该做的是标志X(X&&)X()noexcept,这种特殊的问题消失。

尽管这样,你确切的代码不会抛出,除非some_other_function不采取X而是从X创建了一个类型,该操作可能抛出,或some_other_function身体可以抛出。