Передача ссылок на указатели в 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 для функции.