Передача ссылок на указатели в C++
насколько я могу судить, нет причин, по которым мне не следует разрешать передавать ссылку на указатель в C++. Однако мои попытки сделать это терпят неудачу, и я понятия не имею, почему.
вот что я делаю:
void myfunc(string*& val)
{
// Do stuff to the string pointer
}
// sometime later
{
// ...
string s;
myfunc(&s);
// ...
}
и я получаю эту ошибку:
не удается преобразовать параметр 1 из 'std:: string *' в ' std:: string *&'
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"); }
попробуй:
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 для функции.