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

Does const rvalue references allow extra optimisations for compiler?

本文关键字:优化 编译器 引用 是否 常量      更新时间:2023-10-16

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

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

它将允许通过某种

template<class T>
class Immutable 
{ 
private: 
const T val; 
public: 
operator const T && () { return std::move(val); } 
};

(只是示例代码),或者在我们确定在函数调用期间无法更改值时按const&&传递值。有可能吗,或者有一些未提及的问题?

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


首先,我们需要澄清"被别人改变"是什么意思。

  • 通过另一个线程。在这种情况下,您的问题不适用。您需要使用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.返回值设置为24。这意味着编译器可以假定没有其他代码可以修改a引用的对象(即使a是非 const 引用)。

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

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引用的对象。

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

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

据我了解,右值引用意味着给定的对象是临时的, 因此没有其他人可以访问其数据

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

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

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

乔纳森·韦克利(Jonathan Wakely)在评论中指出:

你的例子证明 const T&& 不必绑定到 临时的,并且可能有多个绑定到 同样的事情:

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

所以这与const&的情况没有什么不同

这是我的看法:

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引用的对象在调用foo期间被修改。

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