const 右值引用是否允许对编译器进行额外优化?

Does const rvalue references allow extra optimisations for compiler?

const C++中函数参数的修饰符表示该函数不能改变参数值,但不保证在函数执行过程中不能被其他人改变。因此,编译器无法依赖数据不变性进行任何优化。

据我了解,右值引用意味着给定对象是临时的,因此没有其他人可以访问其数据。编译器可以在这种情况下进行积极的优化吗?

它可以通过某种

来获得更快的代码
template<class T>
class Immutable 
{ 
private: 
    const T val; 
public: 
    operator const T && () { return std::move(val); } 
};

(只是示例代码),或者当我们确定它们在函数调用期间不能更改时通过 const&& 传递值。有可能吗,还是有一些没有提到的问题?

tl'dr:它不启用任何优化,因为它不以任何方式保证对象未被修改。它只会增加混乱。 不要使用它!


首先我们需要弄清楚"changed by someone else"是什么意思。

  • 来自另一个线程。在这种情况下,您的问题不适用。您需要使用 mutex 或其他机制来保护您的数据。否则编译器会假定没有其他线程修改数据。

  • 同一个线程,在函数未调用(直接或间接)的代码中。不可能。

  • 同一线程,在函数调用(直接或间接)的代码中。

我们显然会处理最后一个:


让我们看一段简单的代码,看看程序集(-O3)

auto foo(int& a)
{
  a = 24;

  return a;
}
foo(int&):                               # @foo(int&)
        mov     dword ptr [rdi], 24
        mov     eax, 24
        ret

如您所见mov eax, 24。 returned 值设置为 24。这意味着编译器可以假定没有其他代码可以修改 a 引用的对象(即使 a 是非常量引用)。

让我们在return之前添加一个函数调用代码:

auto bar() -> void;

auto foo(int& a)
{
  a = 24;
  bar();
  return a;
}
foo(int&):                               # @foo(int&)
        push    rbx
        mov     rbx, rdi
        mov     dword ptr [rbx], 24
        call    bar()
        mov     eax, dword ptr [rbx]
        pop     rbx
        ret

编译器无法访问 bar 的主体,因此它必须考虑到 bar 可以修改 a.[=39 引用的对象=]

现在根据您的问题将 const& 添加到等式中不会改变等式。只能通过在当前函数中调用的代码修改对象

拥有 const&& 不会以任何方式改变这一点。 a引用的对象仍然可以修改。

As I understand rvalue reference means that given object is temporary, so nobody else have access to its data

不正确。右值引用可以绑定到 prvalues(临时)或 xvalues。您自己的示例显示了这一点:

operator const T && () { return std::move(val); } 

这里你绑定到 val 这不是临时的(如果封闭对象不是)。

Jonathan Wakely 在评论中指出:

Your example proves that const T&& doesn't have to be bound to a temporary, and there could be several rvalue references bound to the same thing:

Immutable<int> i{};
const int&& r1 = i;
const int&& r2 = i;

So This is no different to the const& case

这是我的看法:

int g = 24;

auto bar() -> void { g = 11; };

auto foo(const int&& a)
{
  bar();
  return a;
}

auto test()
{
  return foo(std::move(g));
}
test():                               # @test()
        mov     dword ptr [rip + g], 11
        mov     eax, 11
        ret

上面的代码是有效的1)并且表明const int&&参数a所引用的对象在[=的调用过程中被修改了36=].

1)虽然我不是100%确定,但我相当确定