c++ 常量引用和普通参数之间的区别是什么?

ldfqzlk8  于 2023-02-01  发布在  其他
关注(0)|答案(8)|浏览(216)
void DoWork(int n);
void DoWork(const int &n);

有什么区别吗?

inn6fuwd

inn6fuwd1#

重要的区别在于,当通过const引用传递时,不会创建新的对象。在函数体中,参数实际上是传入对象的别名。
因为引用是const引用,所以函数体不能直接更改该对象的值。这与按值传递具有类似的属性,按值传递函数体也不能更改传入的对象的值,在这种情况下,因为参数是副本。
如果参数是一个const引用,但传递给它的对象实际上不是const,那么对象的值可能在函数调用过程中改变。
例如

int a;

void DoWork(const int &n)
{
    a = n * 2;  // If n was a reference to a, n will have been doubled 

    f();  // Might change the value of whatever n refers to 
}

int main()
{
    DoWork(a);
}

另外,如果传入的对象实际上不是const,那么函数可以(即使这是不明智的)通过强制类型转换来更改其值。
例如:

void DoWork(const int &n)
{
    const_cast<int&>(n) = 22;
}

如果传入的对象实际上是const,这将导致未定义的行为。
当参数通过常量引用传递时,额外的代价包括解引用、更差的对象局部性、更少的编译优化机会。
当参数按值传递时,需要创建一个参数副本,这是一个额外的开销。通常,只有当对象类型很大时,才需要考虑这一点。

k3bvogb1

k3bvogb12#

当你传递一个大的结构体/类时,这个区别就更加明显了:

struct MyData {
    int a,b,c,d,e,f,g,h;
    long array[1234];
};
void DoWork(MyData md);
void DoWork(const MyData& md);

当使用"normal"参数时,按值传递参数,从而创建所传递参数的副本。如果使用常量引用,则按引用传递,并且不复制原始数据。
在这两种情况下,都不能从函数内部修改原始数据。

    • 编辑:**

在某些情况下,原始数据可能会被修改,正如Charles Bailey在他的回答中指出的那样。

xdyibdwo

xdyibdwo3#

有三种方法可以在函数中传递值
1.按值传递

void f(int n){
    n = n + 10;
}

int main(){
    int x = 3;
    f(x);
    cout << x << endl;
}

产量:3.缺点:当参数x通过f函数传递时,编译器会在内存中创建x的副本,因此会浪费内存。
1.通过引用传递

void f(int& n){
    n = n + 10;
}

int main(){
    int x = 3;
    f(x);
    cout << x << endl;
}

输出:13。它消除了通过值传递的缺点,但如果程序员不想改变值,则使用常量引用
1.常数参考

void f(const int& n){
    n = n + 10; // Error: assignment of read-only reference  ‘n’
}

int main(){
    int x = 3;
    f(x);
    cout << x << endl;
}

输出:在n = n + 10抛出错误,因为当我们传递const引用参数时,它是只读参数,您无法更改n的值。

gmxoilav

gmxoilav4#

void DoWork(int n);

n是实参值的副本,在函数中修改n的值是法律的的。

void DoWork(const int &n);

n是对实际参数的引用,更改其值是不法律的的。

prdp8dxp

prdp8dxp5#

既然你们都没提到常量关键字...

    • const**关键字修改类型声明的类型或函数参数的类型,防止值发生变化。(来源:MS)

换句话说:通过引用传递参数会暴露被调用方的修改。2使用const关键字可以防止修改。

ntjbwcob

ntjbwcob6#

第一种方法通过传值传递n,也就是说,n的一个副本被发送到函数;第二种方法通过传址传递n,也就是说,一个指向n的指针被发送到函数。
对于int这样的整型类型,作为const引用传递没有多大意义,因为引用的大小通常与引用(指针)的大小相同。在复制开销很大的情况下,通常最好通过const引用传递。

vu8f3i0k

vu8f3i0k7#

首先,没有cv限定引用的概念,所以术语“const reference”是不正确的,通常用来描述“reference to const”,最好开始讨论它的含义。
$8.3.2/1-“CV限定引用是格式错误的,除非通过使用typedef(7.1.3)或模板类型参数(14.3)引入CV限定符,在这种情况下,CV限定符将被忽略。”
以下是不同之处
$13.1 -“只有在参数类型规范最外层的const和volatile类型说明符被忽略;埋在参数类型规范内的const和volatile类型说明符是重要的,并且可用于区分重载函数声明。112)具体而言,对于任何类型T,“指向T的指针”、“指向const T的指针”和“指向volatile T的指针”被认为是不同的参数类型,“指向T的引用”、“指向const T的引用”和“指向volatile T的引用”也是如此。

void f(int &n){
   cout << 1; 
   n++;
}

void f(int const &n){
   cout << 2;
   //n++; // Error!, Non modifiable lvalue
}

int main(){
   int x = 2;

   f(x);        // Calls overload 1, after the call x is 3
   f(2);        // Calls overload 2
   f(2.2);      // Calls overload 2, a temporary of double is created $8.5/3
}
xzv2uavs

xzv2uavs8#

此外,您可以使用const int& x将其初始化为r值,这将导致您无法更改x或将其与其他值绑定。

const int& x = 5; // x is a constant reference to r-value 5
x = 7;            // expression is not a modifable value

相关问题