非常量对象作为具有常量参数的函数的参数 (C++)

Non-constant object as an argument to a function with constant parameter (C++)

提问人:ConventionalProgrammer 提问时间:3/16/2023 最后编辑:Vlad from MoscowConventionalProgrammer 更新时间:3/16/2023 访问量:86

问:

当我在函数中创建一个局部变量并将此变量传递到需要引用常量整数的函数中时,程序工作正常:nummain()dosmth(const int& num)

#include <iostream>

using namespace std;

void dosmth(const int& num) { // Same address. Non-modifiable.

    cout << &num << endl; 
    
    // num++; // Compiler error
}

int main() {
    int num = 10; // Same adress. Modifiable.
    dosmth(num); 
    num++; // No compiler error.
    cout<<&num;
    return 0;
}

当前的 ISO C++ (2020) 标准在第 9.4.3 节中指出:

...... 对类型“cv1 T1”的引用由 type “cv2 T2”如下:

  • 如果引用是左值引用和初始值设定项表达式 是一个左值(但不是位域),而“cv1 T1”是 与“cv2 T2”兼容的参考,

  • 或具有类类型(即 T2 是类类型),其中 T1 与 T2 无关,可以转换为类型的左值 “cv3 T3”,其中“cv1 T1”与“cv3 T3”(此 通过枚举适用的转换来选择转换 函数 (12.4.1.6) 并通过重载选择最佳函数 第(12.4)号决议)。

然后,引用绑定到 Initializer 表达式 Lvalue 第一种情况和左值转换的结果在 第二种情况(或者,在任一情况下,到相应的基类 对象的子对象) .........

换言之,引用绑定到初始值设定项表达式 lvalue(在本例中为 a)。但是,我无法理解函数中本地声明的变量(即)如何由两个函数(和)共享并同时占据相同的虚拟地址,而其类型在这两个函数的范围内不同(一个是只读的,另一个不是)。据我所知,按引用传递会为实际参数创建一个别名,该别名不是副本,而是实际指向实际变量。如果引用根据标准绑定到 a,它现在应该指向 ,但它指向的是一个变量,即 。const intmainintmaindosmthconst intconst intnum

C++ 引用 常量 传递

评论

1赞 Rogue 3/16/2023
如果你拿一些,没有问题,因为仍然不可修改(通过该引用)。如果你有 ,那么它是完全有效的。这归结为CV资格的语义,但总的来说,将“const”视为“我保证不修改”的信号会有所帮助,而不是要求无法修改的东西。const ref&refconst ref&int a = 0;const int& b = a;
0赞 NathanOliver 3/16/2023
你引用的不是说它指的是,它说它的行为好像它指的是一个。它所指的不一定是 .numconst intconst intintconst
1赞 NathanOliver 3/16/2023
通常,您可以随时添加 ,删除它可能会导致问题。const
0赞 ConventionalProgrammer 3/16/2023
@NathanOliver“......它说什么,它的行为就好像它剂量参考......”这是否意味着一种不同于普通常量表达式的抽象?Rogue 给出了一个合理的论点,我相信这证实了我的断言。
0赞 NathanOliver 3/16/2023
@ConventionalProgrammer 是的。从技术上讲,在这种情况下,抛弃和修改它是合法的。那是因为所指的事物是一个非常量对象,修改一个非常量对象是合法的。constnumnum

答:

3赞 Vlad from Moscow 3/16/2023 #1

您声明了一个非常量对象

int num = 10; // Same adress. Modifiable.

所以它可能会被改变。

num++; // No compiler error.

通过常量引用将对象传递给函数。因此,在函数中,对象可能不会被更改。

来自 C++ 20 标准(9.2.9.2 cv 限定符)

3 指向 cv 限定类型的指针或引用实际上不需要 指向或引用 CV 限定的对象,但将其视为 确实;const 限定的访问路径不能用于修改对象 即使引用的对象是非常量对象,并且可以是 通过其他访问路径进行修改。

例如,您可以编写

int x = 10;
const int &crx = x;
int &rx = x;

然后

rx += 20;

但你不能写

crx += 20;

评论

0赞 ConventionalProgrammer 3/16/2023
这就是我问的。如何通过常量引用?毕竟,我所指的事物最初并没有被宣布为常数。
0赞 Rogue 3/16/2023
没关系,您可以将一个非常量值作为常量引用传递,并且在该函数的上下文中,无法修改引用的参数。
0赞 Vlad from Moscow 3/16/2023
@ConventionalProgrammer 请参阅答案中 C++20 标准的引用。
1赞 Svalorzen 3/16/2023
@ConventionalProgrammer 变量的类型是一种语言抽象,它实际上并不存在于机器级别。常量检查由编译器在抽象级别完成,而机器只是处理 CPU 寄存器中包含的一系列位。