c – 从临时返回常量对象和构造
我最近发现了msvc和g / clang编译器之间的区别,这与返回常量对象时RVO的行为有关.一个简单的例子说明了差异:
#include <iostream> class T { public: T() { std::cout << "T::T()n"; } ~T() { std::cout << "T::~T()n"; } T(const T &t) { std::cout << "T::T(const T&)n"; } T(T &&t) { std::cout << "T::T(T&&)n"; } T(const T &&t) { std::cout << "T::T(const T&&)n"; } }; const T getT() { T tmp; return tmp; } int main() { T nonconst = getT(); } 在启用优化的情况下,两个示例都将仅生成T()和~T()调用,这是由于RVO(这会忽略返回类型的常量)所期望的.但没有它们,结果会有所不 clang或g with -fno-elide-constructors规则的一切: T::T() T::T(T&&) // from non-const local tmp variable to temp storage (const,due to return-type) T::~T() T::T(const T&&) // from constant temp storage to nonconst variable T::~T() T::~T() msvc(2013)忽略了返回类型constness: T::T() T::T(T&&) // from local non-const tmp var to non-const nonconst var T::~T() T::~T() 略有修改: const T getT() { const T tmp; // here const is added return tmp; } clang或g with -fno-elide-constructors,一切如预期的那样: T::T() T::T(const T&&) // from const local tmp var to temp storage (const,due to return-type) T::~T() T::T(const T&&) // from constant temp storage to nonconst variable T::~T() T::~T() msvc(2013): T::T() T::T(const T&&) // from local const tmp var to non-const nonconst var T::~T() T::~T() 所有这些都解释了原始版本中的下一个问题(没有const为tmp):如果禁止像T(const T&& t)= delete那样从常量临时构造; g / clang产生错误:使用删除的函数’T :: T(const T&&)’而msvc则没有. 那么,这是MSVC中的一个错误吗? (它忽略了返回类型规范并打破了建议的语义) 简而言之:msvc编译以下代码,g / clang不编译. #include <iostream> class T { public: T() { std::cout << "T::T()n"; } ~T() { std::cout << "T::~T()n"; } T(const T &t) { std::cout << "T::T(const T&)n"; } T(T &&t) { std::cout << "T::T(T&&)n"; } T(const T &&t) = delete; }; const T getT() { const T tmp; return tmp; } int main() { T nonconst = getT(); // error in gcc/clang; good for msvc } 解决方法
我相信const在这里是一个红鲱鱼.我们可以将示例简化为:
struct T { T() = default; T(T &&) = delete; }; T getT() { T tmp; return tmp; } int main() { T x = getT(); } 这无法在gcc或clang上编译,我相信失败是正确的.无论复制省略是否发生,我们仍然对构造函数执行重载决策.来自[class.copy]:
按照规则,我们执行重载解析,就像对象是右值一样.该重载决策找到T(T&&),它被明确删除.由于这个电话是不正确的,整个表达形式都是不正确的. 复制/移动省略只是一种优化.它将忽略的代码必须始终有效. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |