#c #pointers #reference #pass-by-reference #pass-by-pointer
Вопрос:
Я передаю ссылку на переменную указателя в функцию. Функция что-то сделает и укажет переменную указателя на некоторый объект. Код:
int Foo(Obj* amp;ptr) {
// do something...
ptr = some_address;
return return_value;
}
int main() {
Obj* p = nullptr;
int ret = Foo(p);
// do something with ret
p->DoSomething();
}
Однако все становится сложнее, если я хочу передать ссылку на указатель на const . Я бы хотел, чтобы сама переменная указателя была изменена (отсюда и ссылка), но я не хочу, чтобы указанный Obj
экземпляр изменялся с помощью этого указателя. В моем воображении это должно быть что-то вроде:
int Foo(const Obj* amp;ptr) {
// do something...
ptr = some_address;
return return_value;
}
int main() {
const Obj* p = nullptr;
int ret = Foo(p);
// do something with ret
p->DoSomething(); // this should only work when DoSomething() is const method
}
РЕДАКТИРОВАТЬ: следующая ошибка не может быть воспроизведена и, следовательно, удалена. Этот вопрос сосредоточен на концепции ссылки на указатель, а не на решении проблемы
C выдает эту ошибку компиляции:
main.cpp:22:10: error: cannot bind non-const lvalue reference of type ‘const Obj*amp;’ to an rvalue of type ‘const Obj*’ 22 | Foo(ptr); | ^~~ main.cpp:14:23: note: initializing argument 1 of ‘void test(const Obj*amp;)’ 14 | int Foo(const Obj* amp;ptr) { | ~~~~~~~~~~~~^~~
Некоторые мысли:
Ошибка не может быть воспроизведена
- Я полагаю, что эта ошибка отображается, когда я пытаюсь передать «неназванную переменную» в ссылочный параметр. В этом случае я передаю переменную
ptr
, что не должно быть проблемой.
ptr
передается в качестве параметра, потому что функция имеет полезное возвращаемое значение. Настройкаptr
больше похожа на побочный продукт этой функции, где вызывающий может игнорировать или использовать.- Я также могу попробовать использовать
Obj**
в качестве параметра, который передается по указателю вместо передачи по ссылке. Это работает, когда aconst Obj**
передается в качестве параметра. Мне просто интересно, что будет, если параметр передается по ссылке.
Комментарии:
1. Какой компилятор вы используете? Кроме того, ваши сообщения об ошибках не соответствуют вашему примеру кода. В ошибке упоминается функция с именем
test
, вызываемая в строке 14 main.cpp , но это явно другая программа по сравнению с тем, что вы показали.2. В сообщении об ошибке ошибочный код указан следующим
Foo(ptr)
образом … Приведенный код не является тем кодом, который выдал сообщение об ошибке. Каков точный типptr
??3. Этот код с тривиальной реализацией
Obj
added не приводит к этой ошибке.4. Извините за путаницу. Тестовая функция , которую я назвал , была
test
вместоFoo
. Я заменилtest
наFoo
после копирования ошибки компиляции на SO и допустил ошибку…5. Что касается компилятора, я изначально скомпилировал свой код, используя как clang , так и это онлайн-тестирование GDB . Однако сейчас я не могу воспроизвести эту ошибку (???) в обеих средах… Я редактирую этот вопрос в один без ошибки.
Ответ №1:
Я не уверен, в чем ваша проблема, поскольку указанный код ошибки не соответствует вашему коду.
Ваш второй пример с int Foo(const Obj* amp;ptr)
работает точно так, как задумано, и отлично компилируется, если вы DoSomething
задаете const .
Прокомментировать ваши три мысли:
- Если вы все правильно настроите, ошибка исчезнет.
- Мне очень, очень не нравятся такие нестандартные вопросы. Гораздо чище возвращать struct или пару int и pointer . Таким образом, вызывающий может записывать
const auto[ret, p] = Foo();
и не должен явно объявлять указатель, который вы, возможно, не захотите использовать. - Передача указателей на указатели выполняется в стиле C из-за отсутствия ссылок и просто усложняет чтение кода без какой-либо пользы.
Ниже приведен слегка измененный код, который отлично компилируется, с лучшим Foo, как упоминалось в моем ответе на 2.:
#include <utility>
struct Obj
{
void DoSomething() const;
};
// This is ugly of course, used just to have a valid ptr to return
Obj global;
int Foo(const Obj* amp;ptr) {
// do something...
ptr = amp;global;
return 5;
}
std::pair<int, const Obj*> BetterFoo()
{
// do something...
return {5, amp;global};
}
int main() {
const Obj* p1 = nullptr;
int ret1 = Foo(p1);
const auto[ret2, p2] = BetterFoo();
p1->DoSomething();
p2->DoSomething();
}
Комментарии:
1. «Я не уверен, в чем ваша проблема» — обычно это причина избежать ответа и вместо этого запросить дополнительную информацию через комментарий (или проголосовать за такой комментарий, если он уже существует — что я и сделал). Цель Stack Overflow — создать хранилище вопросов и ответов для будущих посетителей. Если проблема четко не определена в вопросе, маловероятно, что будущие посетители смогут определить, относится ли вопрос к ним.
Ответ №2:
Один из способов справиться с этой ситуацией — использовать typedef
или using
. Например, using ObjPtr = Obj*;
теперь функция будет int Foo(const ObjPtramp; ptr) { ... }
.
Комментарии:
1.
const ObjPtr
это не то жеconst Obj *
самое , что . Первый представляет собой постоянный указатель на непостоянный объект, в то время как второй является непостоянным указателем на постоянный объект. OP специально запросил указатель на const, которыйObjPtr
не может быть доставлен.2. Как писал @JaMiT, делая это, вы делаете сам указатель const — что означает, что невозможно переназначить указатель внутри Foo. Таким образом, с вашим «решением» функция Foo больше не будет компилироваться.