通过引用传递参数到指针问题

Posted

技术标签:

【中文标题】通过引用传递参数到指针问题【英文标题】:Argument passing by reference to pointer problem 【发布时间】:2011-11-10 14:59:26 【问题描述】:

每次我尝试编译我的代码时都会出错:

cannot convert parameter 1 from 'int *' to 'int *&'

测试代码如下所示:

void set (int *&val)
   *val = 10;


int main()
   int myVal;
   int *pMyVal = new int;
   set(&myVal); // <- this causes trouble
   set(pMyVal); // <- however, this doesn't

我想一次性调用该函数,而不需要在某处创建指针来传递它。而且由于指针没有构造函数,所以不能这样做:set(int*(&amp;myVal));

有没有其他方法可以通过引用传递指针而不需要创建临时变量?

编辑:顺便说一句,我知道为什么代码无法编译(我只是传递了可能是 int 而不是实际指针的地址)。问题是还能怎么做。

【问题讨论】:

如果你不想创建一个指针,为什么你要求函数获取一个指针(通过引用)?为什么不set (int &amp;v)v=10; 因为我的类正在存储值,但是该值随后作为指针传递给另一个存储该指针的类。这个指针必须通过引用函数中的指针参数来设置,否则传递的指针并不是真正指向值,而是指向它的副本。在设置此指针之前,我不想创建临时指针只是为了能够传递它。这就是为什么我没有介绍实际问题,而只是介绍了与我的问题相似且更容易的问题。 【参考方案1】:

对非常量的引用不能绑定到右值。 &amp; 运算符的结果是一个右值。看看the difference between lvalues and rvalues 或阅读a good C++ book。

此外,在您的上下文中,您不需要通过引用传递。以下也可以:

void set (int *val)
   *val = 10;

如果您要执行此类操作,则需要参考;

void set (int*& val)
   val = new int; //notice, you change the value of val, not *val
   *val = 10;

【讨论】:

所以int* const&amp; p是指向整数的常量指针的引用,所以它可以被赋值为右值,对吧? @Raven:是的,这是正确的。但是不需要通过引用 const 来传递内置类型。它不如按值传递有效。对于用户定义的类型,最好通过引用来传递 const【参考方案2】:

问题是,int*&amp;val 只能传递一个左值,而 &myVal 的结果不是。通过将签名更改为void set(int* const&amp; val),它告诉编译器您不会更改指针的值。

但是,您通常不会这样做,只是因为如果您不打算更改指针的值,那么按值传递指针是传递值的最直接方式。如果你要改变指针的值,那么你需要创建一个临时的来接收结果。

【讨论】:

【参考方案3】:

可以看到如下示例代码:

#include <iostream>
using namespace std;

void change(int*& ptr) 
    cout << endl;
    cout << "==================change(int*& ptr)====================" << endl;
    cout << "    &ptr = " << &ptr << endl;
    cout << "    ptr  = " << ptr << endl;
    cout << "=======================================================" << endl;
    cout << endl;
    *ptr *= *ptr;


int main(void) 
    int* ptrNumber = new int(10);

    cout << endl;
    cout << "&ptrNumber = " << &ptrNumber << endl;
    cout << "ptrNumber = " << ptrNumber << endl;
    cout << ">>> *ptrNumber = " << *ptrNumber << endl;
    change(ptrNumber);
    cout << "<<< *ptrNumber = " << *ptrNumber << endl;

我安装了Cygwin,用g++编译了上面的源码,二进制文件是out_pointer.exe。 执行out_pointer.exe,输出如下:

$ ./out_pointer.exe

&ptrNumber = 0x28ac3c
ptrNumber = 0x800102c0
>>> *ptrNumber = 10

==================change(int*& ptr)====================
    &ptr = 0x28ac3c
    ptr  = 0x800102c0
=======================================================

<<< *ptrNumber = 100

从上面的输出,我们看到

&ptrNumber = &ptr

所以,ptr 是 ptrNumber 的别名。您可以通过修改 ptr 来修改函数 void change(int*& ptr) 内的 ptrNumber。例如,您可以将 ptr 指向另一个内存位置,如下所示:

#include <iostream>
using namespace std;

void change(int*& ptr) 
    cout << endl;
    cout << "==================change(int*& ptr)====================" << endl;
    cout << "    &ptr = " << &ptr << endl;
    cout << "    >>> ptr = " << ptr << endl;
    ptr = new int(20);
    cout << "    <<< ptr = " << ptr << endl;
    cout << "=======================================================" << endl;
    cout << endl;


int main(void) 
    int* ptrNumber = new int(10);

    cout << endl;
    cout << ">>> &ptrNumber = " << &ptrNumber << endl;
    cout << ">>> ptrNumber = " << ptrNumber << endl;
    cout << ">>> *ptrNumber = " << *ptrNumber << endl;
    change(ptrNumber);
    cout << "<<< &ptrNumber = " << &ptrNumber << endl;
    cout << "<<< ptrNumber = " << ptrNumber << endl;
    cout << "<<< *ptrNumber = " << *ptrNumber << endl;

新输出:

$ ./out_pointer.exe

>>> &ptrNumber = 0x28ac3c
>>> ptrNumber = 0x800102c0
>>> *ptrNumber = 10

==================change(int*& ptr)====================
    &ptr = 0x28ac3c
    >>> ptr = 0x800102c0
    <<< ptr = 0x80048328
=======================================================

<<< &ptrNumber = 0x28ac3c
<<< ptrNumber = 0x80048328
<<< *ptrNumber = 20

【讨论】:

【参考方案4】:

在这个地方可以找到一个非常简单的例子。 http://markgodwin.blogspot.de/2009/08/c-reference-to-pointer.html

【讨论】:

【参考方案5】:

&amp;myval 是一个右值(int* 类型),因为它是一个临时值。它是一个指针,但您不能修改它,因为它只是动态创建的。但是,您的函数 set 需要非常量引用,因此您不能将其传递给临时函数。

相比之下,pMyVal 是一个命名变量,因此是一个左值,因此它可以作为非常量引用传递。

【讨论】:

我会说&amp;myval 的类型是int * const &amp; 抱歉,这在很多方面都是不正确和误导的。一方面,const int * &amp; 是“对指向 const int 的指针的引用”,而不是“对常量指针的引用”。其次,对 const 和右值的引用是有区别的(右值 don't 的类型为 const T&amp;)。第三,对象不必被命名为左值。 @jpalecek:我没有说左值必须是命名对象,我说这个命名对象是左值。不是所有的猫…… &amp;myval is of type int * const &amp; 完全错误。 &amp;myvalint* 类型的右值 @Kerrek:广告命名对象:我发现您的表述具有误导性,它表明“左值”是“命名对象”的同义词。你可以写“......是一个命名变量(它是一个左值)......”或其他东西。对于另一个问题,请阅读 Armen 所写的内容。

以上是关于通过引用传递参数到指针问题的主要内容,如果未能解决你的问题,请参考以下文章

指针作为函数参数传递的注意事项

是否传递指针参数,在 C++ 中按值传递?

小白学习C++ 教程八在C++指针传递引用和Const关键字

C++ 值传递指针传递引用传递详解

C++中函数参数的传递方式有哪几种

将 lambda 作为参数传递 - 通过引用或值?