Передача ссылок на указатели в C++
Вопрос
Насколько я могу судить, нет причин, по которым мне нельзя было бы разрешить передавать ссылку на указатель в C++.Однако мои попытки сделать это терпят неудачу, и я понятия не имею, почему.
Вот что я делаю:
void myfunc(string*& val)
{
// Do stuff to the string pointer
}
// sometime later
{
// ...
string s;
myfunc(&s);
// ...
}
И я получаю эту ошибку:
невозможно преобразовать параметр 1 из 'std::string *' в 'std::string *&'
Решение
Ваша функция ожидает ссылку на фактический указатель строки в вызывающей области, а не на анонимный указатель строки. Таким образом:
string s;
string* _s = &s;
myfunc(_s);
должен хорошо скомпилироваться.
Однако это полезно только в том случае, если вы намереваетесь изменить указатель, передаваемый функции. Если вы намереваетесь изменить саму строку, вы должны использовать ссылку на строку, как предложил Sake. Имея это в виду, должно быть более очевидно, почему компилятор жалуется на ваш оригинальный код. В вашем коде указатель создается «на лету», изменение этого указателя не имело бы никакого значения, и это не то, что предназначено. Идея ссылки (против указателя) состоит в том, что ссылка всегда указывает на реальный объект.
Другие советы
Проблема в том, что вы пытаетесь привязать временную ссылку к ссылке, которую 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);
РЕДАКТИРОВАТЬ:
Это называется 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");
}
& amp; 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);
// ...
}
РЕДАКТИРОВАТЬ: Я экспериментировал с некоторыми, и обнаружил, что вещи немного тоньше, чем я думал. Вот то, что я сейчас считаю точным ответом.
& amp; s
не является lvalue, поэтому вы не можете создать ссылку на него, если тип ссылки не является ссылкой на const
. Так, например, вы не можете сделать
string * &r = &s;
но вы можете сделать
string * const &r = &s;
Если вы поместите аналогичное объявление в заголовок функции, оно будет работать.
void myfunc(string * const &a) { ... }
Есть еще одна проблема, а именно временные. Правило заключается в том, что вы можете получить ссылку на временный объект только в том случае, если он является const
. Таким образом, в этом случае можно утверждать, что & amp; s является временным, и поэтому должно быть объявлено const
в прототипе функции. С практической точки зрения это не имеет значения в этом случае. (Это либо значение, либо временное значение. В любом случае, применяется то же правило.) Однако, строго говоря, я думаю, что это не временное значение, а значение. Интересно, есть ли способ отличить их? (Возможно, просто определено, что все временные значения являются r-значениями, а все ненулевые значения являются временными значениями. Я не специалист по стандарту.)
При этом ваша проблема, вероятно, находится на более высоком уровне. Почему вы хотите ссылку на адрес 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 (" строка * & amp; val ") само по себе не имеет никакого смысла. & Quot; строка * & амп; Val & Quot; подразумевает "string val", * и & amp; отменяет друг друга. Наконец, нельзя передавать строковую переменную в функцию (" string val "). Только основные типы данных могут быть переданы в функцию, для других типов данных необходимо передать в качестве указателя или ссылки. Вы можете иметь либо строку & amp; val или строка * val для функции.