Передача ссылок на указатели в C ++ - PullRequest
116 голосов
/ 05 мая 2009

Насколько я могу судить, нет причин, по которым мне нельзя разрешать передавать ссылку на указатель в C ++. Тем не менее, мои попытки сделать это терпят неудачу, и я понятия не имею, почему.

Вот что я делаю:

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

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

И я получаю эту ошибку:

не может преобразовать параметр 1 из 'std :: string *' в 'std :: string * &'

Ответы [ 10 ]

114 голосов
/ 05 мая 2009

Ваша функция ожидает ссылку на фактический указатель строки в вызывающей области, а не на анонимный указатель строки. Таким образом:

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

должно скомпилироваться просто отлично.

Однако это полезно, только если вы намереваетесь изменить указатель, который вы передаете функции. Если вы намереваетесь изменить саму строку, вы должны использовать ссылку на строку, как предложил Sake. Имея это в виду, должно быть более очевидно, почему компилятор жалуется на ваш оригинальный код. В вашем коде указатель создается «на лету», изменение этого указателя не имело бы никакого значения, и это не то, что предполагается. Идея ссылки (против указателя) состоит в том, что ссылка всегда указывает на реальный объект.

83 голосов
/ 05 мая 2009

Проблема в том, что вы пытаетесь привязать временную ссылку к ссылке, которую 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;
}
10 голосов
/ 05 мая 2009

Измените его на:

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

EDIT:

Это называется 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 голосов
/ 05 мая 2009

&s создает временный указатель на строку, и вы не можете сделать ссылку на временный объект.

3 голосов
/ 05 мая 2009

Попробуйте:

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);
    // ...
}
2 голосов
/ 05 мая 2009

РЕДАКТИРОВАТЬ: Я экспериментировал с некоторыми, и обнаружил, что вещи немного тоньше, чем я думал. Вот то, что я сейчас считаю точным ответом.

&s не является lvalue, поэтому вы не можете создать ссылку на него, если тип ссылки не является ссылкой на const. Так, например, вы не можете сделать

string * &r = &s;

но вы можете сделать

string * const &r = &s;

Если вы поместите аналогичное объявление в заголовок функции, оно будет работать.

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

Есть еще одна проблема, а именно временные. Правило заключается в том, что вы можете получить ссылку на временный объект, только если он равен const. Так что в этом случае можно утверждать, что & s является временным, и поэтому должно быть объявлено const в прототипе функции. С практической точки зрения это не имеет значения в этом случае. (Это либо значение, либо временное значение. В любом случае, применяется то же правило.) Однако, строго говоря, я думаю, что это не временное значение, а значение. Интересно, есть ли способ отличить их? (Возможно, просто определено, что все временные значения являются r-значениями, а все ненулевые значения являются временными значениями. Я не специалист по стандарту.)

При этом ваша проблема, вероятно, находится на более высоком уровне. Почему вы хотите ссылку на адрес s? Если вы хотите ссылку на указатель на s, вам нужно определить указатель как в

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

Если вам нужна ссылка на s или указатель на s, сделайте это просто.

1 голос
/ 20 июня 2013

Я только что использовал ссылку на указатель, чтобы сделать все указатели в удаленном двоичном дереве, кроме корневого, безопасным. Чтобы сделать указатель безопасным, мы просто должны установить его в 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).

0 голосов
/ 01 марта 2017

Добро пожаловать в C ++ 11 и ссылки на rvalue:

#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(). Наконец, это временно.

0 голосов
/ 05 мая 2009

myfunc ("string * & val") само по себе не имеет никакого смысла. «string * & val» подразумевает «string val», * и & отменяет друг друга. Наконец, нельзя передавать строковую переменную в функцию («string val»). Только основные типы данных могут быть переданы в функцию, для других типов данных необходимо передать в качестве указателя или ссылки. Вы можете использовать либо строку & val, либо строку * val для функции.

0 голосов
/ 05 мая 2009

Я знаю, что возможно передавать ссылки на указатели, я делал это на прошлой неделе, но я не могу вспомнить, каков был синтаксис, так как ваш код сейчас выглядит правильным для моего мозга. Однако другой вариант - использовать указатели указателей:

Myfunc(String** s)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...