常量参数"real"常量吗?
Are const arguments "real" constants?
AFAIK 从常量变量中删除常量是未定义的行为:
const int i = 13;
const_cast<int&>(i) = 42; //UB
std::cout << i << std::endl; //out: 13
但是常量函数参数是"实"常量吗?让我们考虑以下示例:
void foo(const int k){
const_cast<int&>(k) = 42; //UB?
std::cout << k << std::endl;
}
int main(){
foo(13); //out: 42
}
似乎编译器不会对const int k
应用与const int i
相同的优化。
第二个例子中有UB吗?const int k
帮助编译器优化代码还是编译器只检查常量正确性,仅此而已?
例
const int i = 13;
中的i
可以用作常量表达式(作为模板参数或案例标签(,并且尝试修改它是未定义的行为。如此是为了向后兼容没有constexpr
的 C++11 之前的代码。
声明void foo(const int k);
和void foo(int k);
声明相同的函数;参数的顶级const
不参与函数的签名。参数k
必须按值传递,因此不能是"真实"常量。抛弃它的恒定性并不是未定义的行为。编辑:但是任何修改它的尝试仍然没有定义,因为它是 const 对象 [basic.type.qualifier] (1.1(:
const 对象是 const T 类型的对象或此类对象的不可变子对象。
通过 [dcl.type.cv] 4 个常量对象无法修改:
除了可以修改任何声明为 mutable (10.1.1( 的类成员之外,任何在其生存期 (6.8( 期间修改 const 对象的尝试都会导致未定义的行为。
由于函数参数具有自动存储持续时间,因此 [basic.life] 10 也无法创建其存储中的新对象:
在具有静态、线程或自动存储持续时间的 const 完整对象所占用的存储中创建新对象,或者在此类 const 对象在其生存期结束之前用于占用的存储中创建新对象,会导致未定义的行为。
目前还不清楚,如果有计划抛弃它的恒常性,为什么k
首先被宣布为const
?它的唯一目的就是混淆和混淆。
一般来说,我们应该在任何地方都支持不变性,因为它可以帮助人们推理。它还可以帮助编译器进行优化。然而,当我们只声明不变性而不尊重它时,它的作用恰恰相反并令人困惑。
我们应该支持的其他事情是纯函数。这些不依赖于或修改任何外部状态,也没有副作用。这些也更容易推理和优化人员和编译器。 目前,此类函数可以声明为constexpr
。但是,将按值参数声明为const
对我的知识没有任何帮助,即使在constexpr
函数的上下文中也是如此。
但是常量函数参数是"实"常数吗?
我认为答案是肯定的。
例如,它们不会存储在 ROM 中,因此丢弃 const 至少看起来可以正常工作。但我对标准的解读是参数的类型是const int
,因此它是一个const 对象([basic.type.qualifier](,因此修改它是未定义的([dcl.type.cv](。
您可以相当轻松地确认参数的类型:
static_assert( std::is_same_v<const int, decltype(k)> );
第二个例子中有UB吗?
是的,我认为有。
const int k 是否帮助编译器优化代码,或者编译器只是检查 const 正确性,仅此而已?
理论上,编译器可以假设在下面的示例中k
不会通过调用g(const int&)
来更改,因为修改k
将是 UB:
extern void g(const int&);
void f(const int k)
{
g(k);
return k;
}
但在实践中,我认为编译器不会利用这一点,而是假设k
可能会被修改(编译器资源管理器演示(。
我不确定你所说的"真正的"常量是什么意思,但在这里。
您的const int i
是任何函数之外的变量声明。 由于修改该变量会导致未定义行为,因此编译器可以假设其值永远不会更改。 一个简单的优化是,无论你从i
读取的任何地方,编译器都不必去从主内存中读取值,它可以发出程序集以直接使用该值。
您的const int k
(或更有趣的const int & k
(是一个函数参数。 它所承诺的只是这个函数不会改变k
的值。 这并不意味着它不能在其他地方更改。 函数的每次调用都可以具有不同的k
值。
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 什么时候在C++中返回常量引用是个好主意
- 代理对象的常量正确性
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 通过多个头文件使用常量变量
- 在cuda线程之间共享大量常量数据
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 是默认情况下分配给char数组常量的值
- 私有类型的静态常量成员
- 类似枚举的计算常量
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 为什么我可以通过引用修改常量返回
- 如何创建长度由常量参数指定的数组
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- 隐式常量/非常量运算符布尔
- 非常量变量只读位置的赋值
- 常量参数"real"常量吗?