Передача ссылок на указатели в C++


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

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

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

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

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

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

10 104

10 ответов:

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

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

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

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

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

меняем его на:

  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");

}

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

попробуй:

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);
    // ...
}

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

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

string * &r = &s;

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

string * const &r = &s;

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

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

там другой вопрос, а именно, временные. Правило заключается в том, что вы можете получить ссылку на временный только в том случае, если это const. Поэтому в этом случае можно утверждать, что &S является временным, и поэтому должен быть объявлен const в прототипе функции. С практической точки зрения это не имеет никакого значения в данном случае. (Это либо значение rvalue, либо временное. В любом случае, действует то же самое правило.) Однако, строго говоря, я думаю, что это не временное, а rvalue. Интересно, есть ли способ отличить между ними двумя. (Возможно, просто определено, что все временные значения являются rvalues, а все не-lvalues являются временными. Я не эксперт по стандарту.)

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

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

если вы хотите ссылку на s или указатель на s выполните простой вещь.

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

Добро пожаловать на 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), который является адресом строки.

вы можете изменить указатель, и никто не будет заботиться. Это один из аспектов того, что такое rvalue в первую очередь.

будьте осторожны: значение указателя допустимо только до myfunc() возвращает. Наконец, это временно.

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

Myfunc(String** s)

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