对非常量变量的常量引用可以转换为非常量引用,然后可以通过引用修改基础对象。它是否也适用于函数声明中的常量引用?
也就是说,在下面的代码中,func()是否允许更改'a',前提是'a'最初不是const?这是否会导致未定义的行为?
void func(const int& arg);
int main()
{
int a = 5; //non-const
func(a);
std::cout << a; //Can func modify 'a' through a const-cast and thus output ≠5?
}
字符串
我问这个问题是因为这会阻止编译器进行优化,因为它会在func求值后被迫再次查找'a'的值;特别是如果func的定义在另一个翻译单元中。
1条答案
按热度按时间zd287kbt1#
是的,可以。
调用
func
将创建一个引用,该引用具有“不必要的”const
:对cv限定类型的指针或引用不需要实际指向或引用cv限定的对象,但会被当作是这样;[...]
func
可以用const_cast
删除这个“不必要的”const
:字符串
在本例中,
func
* 可以 * 修改a
到evil
,因为a
不是const对象。但是,如果a
实际上是const
,那么这将是未定义的行为:在const对象的生存期内,任何修改const对象的尝试都会导致未定义的行为。
一般来说,如果给一个函数一个引用或指针,它可以简单地
const_cast
或reinterpret_cast
引用它想要的任何类型。但是,如果被访问的对象类型与引用的类型不相似,则在大多数情况下这是未定义的行为。访问可能未定义,const_cast
或reinterpret_cast
本身就可以。对编译器优化的影响
考虑以下简化示例:
型
通过优化,clang输出:
型
这段代码的缺点是
func
可以修改a
。mov dword ptr [rsp + 4], 5
将a
存储在堆栈上func
后,mov eax, dword ptr [rsp + 4]
从堆栈加载a
如果改为写入
const int a = 5;
,则程序集以mov eax, 5
结束,并且a
不会溢出到堆栈上,因为它不能被func
修改。这样更有效率。