在C ++中传递对指针的引用


130

据我所知,没有理由不应该允许我将引用传递给C ++中的指针。但是,我这样做的尝试失败了,我也不知道为什么。

这就是我在做什么:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

我收到此错误:

无法将参数1从'std :: string *'转换为'std :: string *&'

Answers:


126

您的函数期望在调用范围内引用实际的字符串指针,而不是匿名字符串指针。从而:

string s;
string* _s = &s;
myfunc(_s);

应该编译就好了。

但是,这仅在您打算修改传递给函数的指针时才有用。如果您打算修改字符串本身,则应使用Sake建议的对该字符串的引用。考虑到这一点,应该更加清楚为什么编译器会抱怨您的原始代码。在您的代码中,指针是“即时”创建的,修改该指针不会有任何后果,这不是我们想要的。引用(相对于指针)的想法是,引用始终指向实际对象。


86

问题在于您正在尝试将临时绑定到引用,除非引用为,否则C ++不允许const

因此,您可以执行以下任一操作:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}


void myfunc2(string* const& val)
{
    // Do stuff to the string pointer
}

int main()
// sometime later 
{
    // ...
    string s;
    string* ps = &s;

    myfunc( ps);   // OK because ps is not a temporary
    myfunc2( &s);  // OK because the parameter is a const&
    // ...

    return 0;
}

用Burr先生在第2个示例中的方式写出该类型特别有启发性,string* const& val而不是像例如const string* &val。在我看来,这显然是对字符串的const 引用,指针。我个人更喜欢用书面形式T const&而不是const T&声明形式来获得确切的说明。
fish2000

1
Nit pick(不是批评):对我来说,bind a temporary to the reference此答案中的短语比@Chris'as更清晰reference to an actual string pointer in the calling scope, not an anonymous string pointer。无论如何,从我的角度来看,两者都可能是正确的。
kevinarpe

1
@ fish2000不仅如此,const string*&而且string* const&实际上是不同的类型。第一个是对a的不const引用const string*,而第二个是对a的const引用string*
贾斯汀时间-恢复莫妮卡

@ fish2000提防“prefering”的T const&const T&-作为@Justin时指出,他们是不同类型的。它可能没有结果的时候,但是在其他情况下,这将是绝对关键的喜欢一个或另一个,就像喜欢intdouble
omatai

3
@ fish2000-一个说“这里是您可以更改为无法更改的参考”,而另一个说“这里是您不能更改为可以更改的参考”。在给出的这个示例中,您根本无法将两者互换。
omatai '16

10

更改为:

  std::string s;
  std::string* pS = &s;
  myfunc(pS);

编辑:

这被称为ref-to-pointer,您不能将临时地址作为对函数的引用。(除非是const reference)。

虽然,我已经显示 std::string* pS = &s;(指向局部变量的指针),它的典型用法是:当您希望被调用者更改指针本身而不是它所指向的对象时。例如,一个分配内存并为其分配给其参数的内存块分配地址的函数必须引用一个指针或一个指向指针的指针:

void myfunc(string*& val)
{
//val is valid even after function call
   val = new std::string("Test");

}

5

&s 产生指向字符串的临时指针,并且您不能引用临时对象。


4
这是不完全正确-你可以做一个参考const的临时
1800信息

3

尝试:

void myfunc(string& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(s);
    // ...
}

要么

void myfunc(string* val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

对于我正在做的事情,我需要指针的地址以及指针本身。我不想按值传递指针。
亚历克斯

仍然不明白您要完成什么。您不能仅仅因为“字符串s”不是指针而拥有“字符串s”的“指针的地址”。
清酒

@Alex:我认为您需要检测该字符串是否与您要存储的另一个字符串完全相同,而不仅仅是它们的内容是否相同。如果是这种情况,请注意,您可以对引用使用address-of运算符,它将为您获取被引用对象的地址:void f(std :: string const&s){std :: string const * p =&s; }
DavidRodríguez-dribeas,2009年

3

编辑:我做了一些实验,发现事情比我想象的要微妙。我现在认为这是一个准确的答案。

&s不是左值,因此除非引用的类型为,否则您无法创建对其的引用const。因此,例如,您不能

string * &r = &s;

但是你可以做

string * const &r = &s;

如果在函数头中放置类似的声明,它将起作用。

void myfunc(string * const &a) { ... }

还有另一个问题,即临时工。规则是,只有在临时目录下,您才能获得对它的引用const。因此,在这种情况下,可能会说&s是临时的,因此必须声明const在函数原型中。从实际的角度来看,在这种情况下没有区别。(它可以是一个右值,也可以是一个临时值。无论哪种方式,都适用相同的规则。)但是,严格来说,我认为这不是一个临时值,而是一个右值。我想知道是否有办法区分两者。(也许只是简单地定义了所有临时变量都是右值,而所有非左值都是临时值。我不是标准专家。)

话虽如此,您的问题可能在更高的层次上。为什么要引用地址s?如果要引用指向的指针s,则需要定义一个指针,如下所示:

string *p = &s;
myfunc(p);

如果您要引用s或指向s,请做直接的事情。


1

我刚刚利用了对指针的引用来使已删除的二叉树中除根安全以外的所有指针都安全。为了使指针安全,我们只需要将其设置为0。我无法使删除树的函数(仅保留根)接受指针的引用,因为我将根(此指针)用作第一个输入以左右移动。

void BinTree::safe_tree(BinTree * &vertex ) {
    if ( vertex!=0 ) {  // base case
        safe_tree(vertex->left);    // left subtree.
            safe_tree(vertex->right);   //  right subtree.
          // delete vertex;  // using this delete causes an error, since they were deleted on the fly using inorder_LVR. If inorder_LVR does not perform delete to the nodes, then, use delete vertex;
        vertex=0;  // making a safe pointer
    }
} // end in

最重要的是,当形式参数是(this)指针时,对指针的引用无效。


1

欢迎使用C ++ 11和右值引用:

#include <cassert>
#include <string>

using std::string;

void myfunc(string*&& val)
{
    assert(&val);
    assert(val);
    assert(val->c_str());
    // Do stuff to the string pointer
}

// sometime later 
int main () {
    // ...
    string s;
    myfunc(&s);
    // ...
}

现在,您可以访问指针的值(由引用val),它是字符串的地址。

您可以修改指针,没有人会在意。这就是右值首先的一个方面。

注意:指针的值仅在myfunc()返回之前有效。最后,这是暂时的。


-1

我知道传递指针的引用是可行的,我上周做了,但是我不记得语法是什么,因为您的代码现在对我而言似乎是正确的。但是,另一个选择是使用指针的指针:

Myfunc(String** s)

-8

myfunc(“ string *&val”)这本身没有任何意义。“ string *&val”表示“ string val”,*和&相互抵消。最后,不能将字符串变量传递给函数(“字符串val”)。只能将基本数据类型传递给函数,因为其他数据类型需要作为指针或引用传递。您可以对函数使用string&val或string * val。


4
在所有级别上都是错误的。请刷新您的var声明语法。
阿里
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.