编译器可以自动生成std :: move以最后使用左值吗?

时间:2013-03-13 13:52:01

标签: c++ c++11 rvalue-reference

这样的代码经常出现在r值引用文章中:

Dave Abrams: Move It With Rvalue References

void g(X);

void f()
{
    X b;
    g(b);              // still need the value of b
    …
    g( std::move(b) ); // all done with b now; grant permission to move
}

编译器是否可以自动生成此优化,即检测l值是否会被破坏并且可能会被移除,或者这将违反标准,假设编译器不知道任何事情的一般情况关于如何为X类实现移动,复制或破坏?

如果允许这样的优化,是否由某些编译器在实践中执行?

3 个答案:

答案 0 :(得分:7)

没有。考虑:

using X = std::shared_ptr<int>;
void g(X);
void f() {
    X b = std::make_shared<int>();
    int &i = *b;
    g(b);              // last use of 'b'
    i = 5;
}

通常,编译器不能假设更改X的副本,移动和析构函数的语义将是合法的更改,而不对围绕b的使用的所有代码进行分析(即,整个fg以及其中使用的所有类型。

实际上,在某些情况下,可能需要进行全程序分析:

using X = std::shared_ptr<std::lock_guard<std::mutex>>;
std::mutex i_mutex;
int i;
void g(X);
void f() {
    X b = std::make_shared<std::lock_guard<std::mutex>>(i_mutex);
    g(b);              // last use of 'b'
    i = 5;
}

如果移动了b,则会针对使用i同步i_mutex访问权限的其他线程引入数据竞争。

答案 1 :(得分:4)

  

(...)假设一般情况,编译器不知道如何为X类实现移动,复制或破坏?

不,编制者不得基于信仰进行优化。

为清楚起见,这个问题与复制省略无关:编制者可能会被允许删除副本,但他们不能随意改变副本。

答案 2 :(得分:4)

可以编译器吗?仅作为明确的语言扩展,因为标准不允许它们在没有它的情况下进行这样的优化。

应该他们这样做了吗?不。g(b)的含义应基于gb的定义。 g应该是一些可调用类型,它有一个重载,可以隐式转换为b。如果可以访问所有可用g的定义以及b的定义,您应该能够确定完全将调用哪个函数。

允许这样做&#34;优化&#34;现在意味着这是不可能的。 g(b) 可能执行移动,但可能不会,具体取决于g(b)在函数中的确切位置。这不是一件好事。

return被允许侥幸逃脱,但仅仅因为它仍具有相同的含义。 return b将始终尝试从b移动,前提是b是一个值生命周期限制的值类型。