C++ C++;编译器是否为方法推断noexcept?

C++ C++;编译器是否为方法推断noexcept?,c++,gcc,compiler-optimization,move-constructor,noexcept,C++,Gcc,Compiler Optimization,Move Constructor,Noexcept,我刚刚注意到我的一个std::vector在调整大小时是在复制而不是移动它的元素-尽管Foo有一个move-ctor: class Foo { // ... Foo(Foo&& other) : id_(other.id_), ptr_(other.ptr_), flag(other.flag) { other.flag = false; }; // ... int id_; void* ptr_;

我刚刚注意到我的一个
std::vector
在调整大小时是在复制而不是移动它的元素-尽管
Foo
有一个move-ctor:

class Foo {
    // ...
    Foo(Foo&& other) : id_(other.id_), ptr_(other.ptr_), flag(other.flag)
    {
        other.flag = false;
    };
    // ...
    int   id_; 
    void* ptr_; 
    bool  flag;
}
然后我读到:

这提醒我,
std::vector
仅在元素的move-ctor声明为
noexcept
时才会使用move构造。当我添加
noexcept
时,会调用move-ctor

我的问题是:为什么给定move-ctor的代码,编译器不确定它是
noexcept
?我的意思是,它可以知道一个事实,异常不能被抛出。另外,标准是不允许推断
noexcept
,还是仅由我的特定编译器进行推断

我正在GNU/Linux上使用GCC 5.4.0。

tl;dr:编译器不允许推断
noexcept
为什么,给定move-ctor的代码,编译器不确定它是noexcept

因为noexcept规范是根据声明而不是定义确定的。这类似于const规范的工作方式。编译器不允许将函数确定为常量,即使其实现没有修改任何成员

标准是否禁止推断无例外

据我所知,是的:

[除了.spec]。。。数据库中缺少异常规范 除析构函数(12.4)或释放函数(3.7.4.2)之外的函数声明符表示 作为所有类型集合的异常规范

推断除所有类型集合之外的其他内容将与此规则相矛盾。当然,当编译器能够证明不能抛出任何异常时,它可以根据“如同”规则优化任何堆栈展开代码,但这种优化不会影响SFINAE内省



有可能引入
noexcept(auto)
,这将是一种让编译器推断noexcept规范的明确方式。

这里有一个明确的列表,说明编译器何时可以假定
noexcept
标准需要安全,以确保强异常保证。分析用户编写的代码不够安全。@RichardCriten:那么你是说编译器应该假设我的代码可能抛出,即使它可以很容易地判断它不会抛出(使用可能抛出的表达式逻辑)?我是说,这可能是标准措辞背后的原因。@einpoklum如果move构造函数位于库中,编译器如何能够假设它不会抛出?它只能看到标题中的声明。@axalis:我可以,但我不是,编译器可以知道/确实知道我不是。。。。当然,如果编译器不知道,那么它必须假设可能存在异常,这是显而易见的。我喜欢你的答案,我不喜欢标准的情况。@einpoklum你想同时推断常量说明符吗?noexcept规范是对函数用户的一种承诺,API的作者可能不希望被要求隐式地对此负责。实际上,它并不完全是对用户的承诺。我的意思是,你可以在一个
noexcept
函数中抛出异常,你只是终止程序而不是找到异常处理程序,对吗?但我想说,每当我们问“我们是否有一个方法/函数某某是
noexcept
?”,有一个方法没有这样或那样标记,编译器知道它是
noexcept
——那么答案是“是”。@einpoklum这是一个承诺,用户不需要处理任何异常,因为没有异常会传播出函数。当然,它不能保证函数不会导致进程终止,但这不是重点。