所以我对移动语义的理解是,它们允许您覆盖用于临时值(右值)的函数并避免潜在的昂贵副本(通过将状态从未命名的临时移动到命名的左值)。
我的问题是为什么我们需要特殊的语义呢?为什么 C++98 编译器不能忽略这些副本,因为它是编译器确定给定表达式是左值还是右值?举个例子:
void func(const std::string& s) {
// Do something with s
}
int main() {
func(std::string("abc") + std::string("def"));
}
即使没有 C++11 的移动语义,编译器仍然应该能够确定传递给的表达式func()
是右值,因此不需要从临时对象复制。那么为什么有区别呢?移动语义的这种应用似乎本质上是复制省略或其他类似编译器优化的变体。
再举一个例子,为什么要费心编写如下代码?
void func(const std::string& s) {
// Do something with lvalue string
}
void func(std::string&& s) {
// Do something with rvalue string
}
int main() {
std::string s("abc");
// Presumably calls func(const std::string&) overload
func(s);
// Presumably calls func(std::string&&) overload
func(std::string("abc") + std::string("def"));
}
似乎const std::string&
重载可以处理这两种情况:像往常一样的左值和作为 const 引用的右值(因为临时表达式根据定义是 const 的)。由于编译器知道表达式何时是左值或右值,它可以决定是否在右值的情况下删除副本。
基本上,为什么移动语义被认为是特殊的,而不仅仅是 C++11 之前的编译器可以执行的编译器优化?