【问题标题】:Can I take a reference of a pointer in C++?我可以引用 C++ 中的指针吗?
【发布时间】:2021-12-14 04:15:56
【问题描述】:

我将 对指针变量的引用 传递给函数。该函数将做一些事情并将指针变量指向某个对象。代码:

int Foo(Obj* &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* &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*&’ to an rvalue of type ‘const Obj*’
   22 |     Foo(ptr);
      |         ^~~
main.cpp:14:23: note:   initializing argument 1 of ‘void test(const Obj*&)’
   14 | int Foo(const Obj* &ptr) {
      |         ~~~~~~~~~~~~^~~

一些想法:

错误无法重现

  1. 我相信当我尝试将“未命名变量”传递到参考参数时会显示此错误。在这种情况下,我将传递变量 ptr,这应该不是问题。
  1. ptr 作为参数传入,因为函数有一个有用的返回值。设置ptr 更像是这个函数的副产品,调用者可以选择忽略或使用。

  2. 我也可以尝试使用Obj**作为参数,它是通过指针传递而不是通过引用传递。这在 const Obj** 作为参数传递时有效。我只是想知道如果参数通过引用传递会怎样。

【问题讨论】:

  • 你用的是什么编译器?此外,您的错误消息与您的代码示例不匹配。该错误提到在 main.cpp 的第 14 行调用了一个名为 test 的函数,但这显然是一个与您显示的程序不同的程序。
  • 错误消息将错误代码列为Foo(ptr)... 给出的代码不是产生错误消息的代码。 ptr 的确切类型是什么??
  • 该代码添加了一个简单的Obj 实现,不会产生该错误。
  • 很抱歉给您带来了困惑。我命名的测试函数是test,而不是Foo。我把编译错误复制到SO后把test换成Foo,报错了……
  • 至于编译器,我最初使用 clang++ 和 online GDB testing 编译了我的代码。但是我现在无法在两种环境中重现此错误(???)...我正在将此问题编辑为一个没有错误的问题。

标签: c++ pointers reference pass-by-reference pass-by-pointer


【解决方案1】:

我不确定您的问题是什么,因为给出的错误代码与您的代码不匹配。

您使用int Foo(const Obj* &ptr) 的第二个示例完全按照预期工作,并且如果您使用DoSomethingconst,则可以正常编译。

评论你的三个想法:

  1. 如果 const 正确,错误就会消失。
  2. 我真的,真的不喜欢这样的外参数。返回一个结构或一对 int 和指针要干净得多。这样,调用者就可以编写const auto[ret, p] = Foo();,而不必显式声明您可能不想使用的指针。
  3. 由于缺少引用,将指针传递给指针是 C 风格的,只会使代码更难阅读,没有任何好处。

如我对 2 的回答中所述,以下是稍加修改的代码,可以很好地编译,也具有更好的 Foo。:

#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* &ptr) {
  // do something...
  ptr = &global;
  return 5;
}

std::pair<int, const Obj*> BetterFoo()
 {
  // do something...
  return {5, &global};
}

int main() {

  const Obj* p1 = nullptr;
  int ret1 = Foo(p1);

  const auto[ret2, p2] = BetterFoo();

  p1->DoSomething(); 
  p2->DoSomething();
}

【讨论】:

  • “我不确定你的问题是什么”——这通常是避免回答的原因,而是通过评论请求更多信息(或者如果一个已经存在——这就是我所做的)。 Stack Overflow 的目的是为未来的访问者创建一个问题和答案的存储库。如果问题中没有明确指出问题,未来的访问者就不太可能知道问题是否与他们有关。
【解决方案2】:

处理这种情况的一种方法是使用typedefusing。例如,using ObjPtr = Obj*; 现在函数将是 int Foo(const ObjPtr&amp; ptr) { ... }

【讨论】:

  • const ObjPtrconst Obj * 不同。前者是指向非常量对象的常量指针,而后者是指向常量对象的非常量指针。 OP 特别请求了一个指向 const 的指针,ObjPtr 未能提供。
  • 正如@JaMiT 所写,通过这样做,您可以使指针本身成为 const - 这意味着不可能在 Foo 中重新分配指针。因此,使用您的“解决方案”, Foo 函数将不再编译。
猜你喜欢
  • 2021-03-15
  • 1970-01-01
  • 2017-06-19
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多