当我不移动任何东西时,为什么 clang 会抱怨已删除的移动 ctor?
Why does clang complain about a deleted move ctor when I don't move anything?
前提 :
#include <iostream>
using namespace std;
class ABC {
public:
ABC() {
cout << "Default constructor ..\n";
}
ABC(const ABC& a) {
cout << "In copy constrcutor ..\n";
}
ABC(ABC&& aa) = delete;
};
int main(int argc, char* argv[]) {
ABC b{ABC{}};
return 0;
}
用 GCC 和 Clang 编译这个
Clang - Apple LLVM version 8.1.0 (clang-802.0.42)
Gcc - 5.4.0 ubuntu
观察
Clang 抱怨删除了 Move 构造函数。
Gcc 一点也不抱怨。并且会正确输出。
问题为什么?
对于 gcc,我知道如果您只是简单地同时初始化左值和右值,它会优化并且不会实际调用复制构造函数并将临时值复制到左值。
为什么 Clang 不同?
我认为(不确定,因此问题)这是 C++ 标准,哪个偏离(或不偏离)?还是我哪里做错了。
编译命令 : g++ --std=c++11 -O3 file.cpp
为了获得更多乐趣,请删除花括号并用括号代替 ;)
ABC b{ABC{}};
至 ABC b(ABC());
,与此问题无关。
EDIT :有人将问题标记为重复问题,但事实并非如此。我明确表示我认为 C++11 标准包括复制省略。然而,CLANG 在像构造函数这样关键的东西上似乎没有相同的行为。
这里是 LINK : http://en.cppreference.com/w/cpp/language/copy_elision
很明显,它说的是 C++11。我信任 cppref.
ABC{}
是临时的,因此 ABC b{ABC{}}
将使用移动构造函数(即使可以省略)。
由于移动构造函数被删除,您应该得到一个错误。
您的 gcc 版本有错误,无法通过错误的省略检测到错误。
在 C++17 中,通过保证复制省略,甚至可以省略已删除的构造函数。因此,您的代码将在 C++17 中编译,仅调用一个默认构造函数。
EDIT : Someone marked the question as a dup, which it is not. I
clearly state that I think C++11 standard includes copy elision.
However, CLANG does not seem to have the same behavior on something as
critical as constructors.
HERE Is the LINK :
http://en.cppreference.com/w/cpp/language/copy_elision
clearly, it says C++11. I trust cppref.
是我把它标记为骗子的。从您链接的页面:
Under the following circumstances, the compilers are permitted, but
not required to omit the copy- and move- (since C++11)construction
When a nameless temporary, not bound to any references, would be copied or moved (since C++11) into an object of the same type (ignoring top-level cv-qualification), the copy/move (since C++11) is omitted. (until C++17)
This optimization is mandatory; see above. (since C++17)
如您所见,移动构造函数将是必需的,因为复制省略不是必需的,而是建议 C++17 之前的版本。 C++17 编译器不应该在相同情况下抱怨删除移动构造函数。
前提 :
#include <iostream>
using namespace std;
class ABC {
public:
ABC() {
cout << "Default constructor ..\n";
}
ABC(const ABC& a) {
cout << "In copy constrcutor ..\n";
}
ABC(ABC&& aa) = delete;
};
int main(int argc, char* argv[]) {
ABC b{ABC{}};
return 0;
}
用 GCC 和 Clang 编译这个
Clang - Apple LLVM version 8.1.0 (clang-802.0.42)
Gcc - 5.4.0 ubuntu
观察 Clang 抱怨删除了 Move 构造函数。
Gcc 一点也不抱怨。并且会正确输出。
问题为什么?
对于 gcc,我知道如果您只是简单地同时初始化左值和右值,它会优化并且不会实际调用复制构造函数并将临时值复制到左值。
为什么 Clang 不同? 我认为(不确定,因此问题)这是 C++ 标准,哪个偏离(或不偏离)?还是我哪里做错了。
编译命令 : g++ --std=c++11 -O3 file.cpp
为了获得更多乐趣,请删除花括号并用括号代替 ;)
ABC b{ABC{}};
至 ABC b(ABC());
,与此问题无关。
EDIT :有人将问题标记为重复问题,但事实并非如此。我明确表示我认为 C++11 标准包括复制省略。然而,CLANG 在像构造函数这样关键的东西上似乎没有相同的行为。
这里是 LINK : http://en.cppreference.com/w/cpp/language/copy_elision
很明显,它说的是 C++11。我信任 cppref.
ABC{}
是临时的,因此 ABC b{ABC{}}
将使用移动构造函数(即使可以省略)。
由于移动构造函数被删除,您应该得到一个错误。
您的 gcc 版本有错误,无法通过错误的省略检测到错误。
在 C++17 中,通过保证复制省略,甚至可以省略已删除的构造函数。因此,您的代码将在 C++17 中编译,仅调用一个默认构造函数。
EDIT : Someone marked the question as a dup, which it is not. I clearly state that I think C++11 standard includes copy elision. However, CLANG does not seem to have the same behavior on something as critical as constructors.
HERE Is the LINK : http://en.cppreference.com/w/cpp/language/copy_elision
clearly, it says C++11. I trust cppref.
是我把它标记为骗子的。从您链接的页面:
Under the following circumstances, the compilers are permitted, but not required to omit the copy- and move- (since C++11)construction
When a nameless temporary, not bound to any references, would be copied or moved (since C++11) into an object of the same type (ignoring top-level cv-qualification), the copy/move (since C++11) is omitted. (until C++17)
This optimization is mandatory; see above. (since C++17)
如您所见,移动构造函数将是必需的,因为复制省略不是必需的,而是建议 C++17 之前的版本。 C++17 编译器不应该在相同情况下抱怨删除移动构造函数。