有点令人惊讶(对我来说),以下两个程序编译到不同的输出,后者有更好的性能(用gcc和clang测试):
#include <vector>
int main()
{
std::vector<int> a(2<<20);
for(std::size_t i = 0; i != 1000; ++i) {
std::vector<int> b(2<<20);
a = b;
}
}
与
#include <vector>
int main()
{
std::vector<int> a(2<<20);
for(std::size_t i = 0; i != 1000; ++i) {
std::vector<int> b(2<<20);
a = std::move(b);
}
}
有人可以向我解释为什么编译器会(或可以)不自动考虑 b
最后一个赋值中的xvalue并应用不带显式的移动语义 std::move
投?
编辑:编译 (g++|clang++) -std=c++11 -O3 -o test test.cpp
编译器不能破坏as-if规则
如§1.9/ 1所述:
本国际标准中的语义描述定义了一个
参数化的非确定性抽象机器。这个国际
标准对合格结构没有要求
实现。特别是,他们不需要复制或模仿
抽象机器的结构。相反,符合实施
需要模仿(仅)抽象的可观察行为
机器如下所述
即编译器无法更改程序的可观察行为。自动(即使没有任何影响)将分配转换为移动分配会破坏此陈述。
复制符号可以稍微改变这种行为,但这受§12.8/ 31的约束。
如果您想使用移动版本,则必须在后一个示例中明确要求它。
让我们看看下一个样本(请忽略 void
返回类型 operator=
):
#include <iostream>
struct helper
{
void operator=(helper&&){std::cout<<"move"<<std::endl;}
void operator=(const helper&){std::cout<<"copy"<<std::endl;}
};
void fun()
{
helper a;
{
helper b;
a = b;
}
}
void gun()
{
helper a;
{
helper b;
a = std::move(b);
}
}
int main()
{
fun();
gun();
}
该 operator=
根据其参数有不同的行为。只有在能够保持可观察行为相同的情况下,才允许编译器优化代码。
考虑到 b
从 fun
一个 xvalue
,虽然它不是 xvalue
在调用的那一刻,它将改变程序的可观察行为,这不是标准所希望的。