【发布时间】:2015-08-02 19:42:26
【问题描述】:
我可以理解编译器在下面的代码中执行复制省略,因为在main() 中完成的所谓的copy-initialization 中没有调用复制和移动构造函数。见live example。
#include <iostream>
struct S {
S() = default;
S(const S&) { std::cout << "copy ctor" << '\n'; }
S(S&&) { std::cout << "move ctor" << '\n'; }
};
int main() {
S s = S();
}
但我不明白为什么当我删除移动构造函数时代码无法编译,如下所示:
#include <iostream>
struct S {
S() = default;
S(const S&) { std::cout << "copy ctor" << '\n'; }
S(S&&) = delete;
};
int main() {
S s = S();
}
在这种情况下,我在 §12.8/32 (N4140) 中找不到任何可能禁止使用或省略 复制构造函数 的内容。这是第 12.8/32 节中引起我注意的一句话,这似乎表明应该在重载决议中考虑复制构造函数:
如果第一个重载决议失败或没有执行,或者如果 所选构造函数的第一个参数的类型不是 对对象类型的右值引用(可能是 cv 限定的), 再次执行重载决议,将对象视为 左值。
编辑
从下面T.C. 的一个 cmets 中,我了解到,当要复制的对象由右值指定时,编译器根据 §12.8/32,不会将复制构造函数视为候选对象对于副本,即使副本无论如何都会被省略。也就是说,最终结果将是使用默认构造函数构造对象s。相反,在这种情况下,标准要求(在哪里??)代码格式错误。除非我对这个方案的理解完全错误,否则这对我来说没有任何意义。
【问题讨论】:
-
重载解析在找到删除的函数时不会失败。被删除的函数不是不存在,它们在某种意义上没有被删除。他们只是非法调用(他们可以被调用,如果你这样做,那就是一个错误)。
-
在任何情况下,从 12.8/32 引用的内容都不适用。
-
在
return语句之外,该段落仅适用于“要复制的对象由左值指定”等情况。S()不是左值。 -
为什么要避免复制省略?
-
@François-MarieArouet 因为
=delete并不意味着“这个函数不存在”。如果您不希望函数存在-> 只是不要声明它。也就是说,=delete表示如果尝试使用这种已删除的函数,编译器会报错。
标签: c++ language-lawyer c++14 copy-elision