斯科特·迈耶斯(Scott Meyers)的新C ++ 11书以下草稿 (第2页第7-21行) 调用堆栈展开和可能展开的区别对代码生成有着惊人的巨大影响。 在一个noexcept函数中,如果一个exception传播出函数,优化器不需要保持运行时堆栈处于不可展开状态,也不必确保noexcept函数中的对象按照构造的相反顺序销毁, 。 结果是更多的优化机会,不仅在noexcept函数体内,而且在函数被调用的地方。 这种灵活性只适用于noexceptfunction。 带有“throw()”exception规范的函数缺less它,就像没有exception规范的函数一样。 相比之下, “C ++性能技术报告”第5.4节则描述了实现exception处理的“代码”和“表格”方式。 特别是,当没有任何exception抛出时,“table”方法显示没有时间开销,只有空间开销。 我的问题是这样的 – 斯科特·迈耶斯(Scott Meyers)谈论的是什么样的优化? 为什么这些优化不适用于throw() ? 他的意见只适用于2006 TR中提到的“代码”方法吗?
默认放置位置new运算符在18.6 [support.dynamic]¶1中用非抛出exception规范声明: void* operator new (std::size_t size, void* ptr) noexcept; 这个函数除了return ptr;外什么也不做return ptr; 所以它是合理的,但是根据5.3.4 [expr.new]¶15这意味着编译器必须检查它在调用对象的构造函数之前不会返回null: -15- [ 注意:除非使用非抛出exception规范(15.4)声明了分配函数,否则它表示抛出std::bad_allocexception来分配存储失败(条款15,18.6.2.1); 否则返回一个非空指针。 如果使用非抛出exception规范声明分配函数,则返回空值以指示分配存储失败,否则返回非空指针。 – 注意 ]如果分配函数返回null,则不进行初始化,不应该调用解除分配函数,new-expression的值应该为空。 在我看来,(特别是安置new ,不是一般的)这个空检查是一个不幸的performance打击,尽pipe很小。 我一直在debugging一些代码,其中放置new被用在一个性能敏感的代码path中,以改善编译器的代码生成,并且在程序集中检查了null。 通过提供一个特定于类的放置位置的new重载,这个重载是通过抛出的exception规范来声明的(即使它不可能抛出),条件分支也被移除了,这也允许编译器为周围的内联函数生成更小的代码。 说安置newfunction的结果可能会抛出,尽pipe它不能 ,是明显更好的代码。 所以我一直想知道是否真的需要空位检查new情况下安置。 它可以返回null的唯一方法是如果你通过它null。 虽然这是可能的,而且显然是合法的,写: void* ptr = nullptr; Obj* obj = new (ptr) Obj(); assert( obj == nullptr ); 我不明白为什么这将是有用的,我build议,如果程序员必须在使用安置之前明确地检查空 Obj* obj = ptr ? new (ptr) […]
我试图创build一个自定义的exception,从std::exception并重写what() 。 起初,我是这样写的: class UserException : public std::exception { private: const std::string message; public: UserException(const std::string &message) : message(message) {} virtual const char* what() const override { return message.c_str(); } }; 这在VS2012中工作正常,但它不会在GCC 4.8中用-std=c++11编译: 错误:宽松抛出说明符'虚拟常量字符* UserException ::什么()const' 所以我加了noexcept : virtual const char* what() const noexcept override 这在GCC中工作正常,但在Visual Studio中不能编译(因为VS 2012不支持noexcept ): 错误C3646:'noexcept':未知的覆盖说明符 什么是处理这个build议的方式? 我想要使用这两个编译器编译相同的代码,我使用C ++ 11function,所以我不能用不同的-std编译。
想象一下,我正在写一些容器模板什么的。 而现在是专门为它的std::swap 。 作为一个好公民,我将通过做这样的事情来启用ADL: template <typename T> void swap(my_template<T>& x, my_template<T>& y) { using std::swap; swap(x.something_that_is_a_T, y.something_that_is_a_T); } 这非常整齐。 直到我想添加一个exception规范。 只要T swap被noexcept ,我的swap就是noexcept noexcept 。 所以,我会写这样的: template <typename T> void swap(my_template<T>& x, my_template<T>& y) noexcept(noexcept(swap(std::declval<T>(), std::declval<T>()))) 问题是,在那里swap需要ADL发现swap或std::swap 。 我该如何处理?
除了分别检查运行时和编译时间之外, throw()和noexcept之间是否还有其他区别? 维基百科的C ++ 11文章指出,C ++ 03抛出说明符已被弃用。 为什么noexcept能够在编译时覆盖所有的内容呢? [注意:我把这个问题和这篇文章提到了 ,但是拿不到折服的可靠原因。]
noexcept关键字可以适用于许多函数签名,但我不确定在实际中何时应该考虑使用它。 根据我迄今为止所读到的内容, noexcept的最后一刻似乎解决了移动构造函数抛出时出现的一些重要问题。 但是,我仍然无法为一些实际问题提供令人满意的答案,这些问题使我更多地了解了noexcept 。 有很多函数的例子,我知道永远不会抛出,但编译器无法自己确定。 在所有这些情况下,我是否应该在函数声明中添加noexcept的内容? 不得不考虑每个函数声明之后是否需要附加noexcept ,这将大大降低程序员的生产力(坦率地说,这将是一个痛苦的屁股)。 对于哪种情况,我应该更加小心使用noexcept ,并且在哪些情况下我可以逃避隐含的noexcept(false) ? 什么时候可以切实地期望在使用noexcept之后观察性能改进? 具体来说,给出一个代码,在添加noexcept之后,C ++编译器能够生成更好的机器代码。 就我个人而言,由于为编译器提供了更多的自由度来安全地应用某些优化,我关心的是noexcept 。 现代编译器以这种方式利用noexcept吗? 如果没有,我可以指望他们中的一些人在不久的将来这样做吗?