【问题标题】: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;}
  • 因为我的类正在存储值,但是该值随后作为指针传递给另一个存储该指针的类。这个指针必须通过引用函数中的指针参数来设置,否则传递的指针并不是真正指向值,而是指向它的副本。在设置此指针之前,我不想创建临时指针只是为了能够传递它。这就是为什么我没有介绍实际问题,而只是介绍了与我的问题相似且更容易的问题。

标签: c++ pointers reference arguments


【解决方案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 所写的内容。
        猜你喜欢
        • 2023-04-06
        • 2011-10-07
        • 2015-10-09
        • 1970-01-01
        • 2014-07-27
        • 2023-03-03
        • 1970-01-01
        • 2019-09-16
        相关资源
        最近更新 更多