【问题标题】:Why and when is worth using pointer to pointer? [duplicate]为什么以及何时值得使用指向指针的指针? [复制]
【发布时间】:2010-06-21 09:15:42
【问题描述】:

可能重复:
How do pointer to pointers work in C?

你好,

虽然我认为我通过了编程的新手阶段,但我仍然有一些问题我无法找到解释。是的,那里有很多“如何做”,但几乎总是没有人解释为什么和/或什么时候一种技术有用。

就我而言,我发现在某些情况下,C++ 中使用了指向指针的指针。指向对象的指针还不够吗?有哪些好处? 应该在什么地方或者什么时候使用一个指向指针的指针?在这件事情上我感觉有点迷失了方向。

我希望经验丰富的专家能够回答这个问题,希望其他没有经验的程序员也能分享这个问题。 ;-)

谢谢大家。

朱伦。

【问题讨论】:

标签: c++ pointers


【解决方案1】:

嗯,这样一个笼统的问题有点难以回答。

C++ 程序员的第一个答案肯定是:不要在 C++ 中使用指针!由于您有很多比指针更安全的方法来处理问题,因此您的目标之一是首先避免它们:)

所以指向指针的指针很少在 C++ 中使用。它们主要用在 C 中。首先,因为在 C 中,字符串是“char*”,所以当您需要“指向 C 字符串的指针”时,您需要以“char**”结尾。其次,由于您在 C 中没有引用,因此当您需要一个修改指针或将指针作为输出值的函数时,您需要提供指向指针参数的指针。您通常会在分配内存的函数中发现这一点,因为它们会为您提供指向已分配内存的指针。

如果你走 C++ 的方式,尽量避免使用指针,你通常有更好的方式。

my2c

【讨论】:

  • -1 “不要在 C++ 中使用指针”。严重地?那么,我应该忘记 DirectX 编程、OpenGL、com 对象、直接 API 调用吗?没有指针的编程有什么意义?这对我来说听起来像是无用的语法糖。
  • @SigTerm:+1 来自我的建议。在需要时降级为低级 API(如著名的&v[0])比在低级代码中完成所有工作要容易得多。近十年来,我编写并维护了几个 MLoC C++ 应用程序的一部分(很可能安装在你的机器上,顺便说一句)。最后我的部分是> 100kLoC。然而那里只有大约三个delete,这主要是出于历史原因。
  • @SigTerm:首先感谢您解释您的反对意见。其次,我不是您所说的 API 专家,但我认为它们是 C API,不是吗?当然,在 C++ 中使用指针的一个用例是使用 C API :) 我也许应该说“在使用 C++ 设计事物时尽量不要使用指针”。当您使用 API 时,您别无选择。此外,由于 OP 问题是关于指向指针的指针,在我看来,这不是设计 C++ 代码以使用指向指针的指针的理想方式。事实上,当我写指针时,我想我认为是原始指针,因为我使用了相当广泛的智能指针;)
  • @sbi:使用指针不等于使用 new/delete。指针在动态内存分配例程之外还有很多用途。
  • @neuro:你的第一个问题是你没有解释为什么你认为指针不好,并且在没有引用任何人或给出合理解释的情况下声称“C++ 程序员不应该使用指针”。这已经值得一票否决。你也没有提到任何指针问题。任何没有合理解释的建议都应该被忽略。像这样的信念会让你编写额外的代码(所以它看起来不错),而实际上却没有编写任何有用的东西。包装器和智能指针不适用于需要良好性能的情况 - 因为它们会增加开销。
【解决方案2】:

在 C 中,参数通过指针传递给改变它的函数。对于旧代码或遗留代码 (int main(int argc, char** argv)),对于将从 C (COM / XPCOM) 访问的代码或由习惯于 C(或 C 风格)的人编写的代码,您将看到相同的 C++。

从“纯 C++”的角度来看,在大多数情况下,使用指向指针的指针是编码风格不佳的标志,因为大多数需要 ** 构造的情况可以(并且应该)重构为使用更安全的替代方案(如 @ 987654323@容器,或*&参数)。

【讨论】:

    【解决方案3】:

    我可以想到两个用例。

    一个是继承自 C 的 数组。在许多情况下,数组会自动衰减为指向其第一个元素的指针。如果你碰巧有一个指针数组,你会得到一个指向那个指针的指针。
    (当你有一个std::vector 的指针时,可能会发生类似的事情,顺便说一句:指针是一个完美的随机访问迭代器,我确实已经看到使用std::vector<>::iterator 的指针的std lib 实现。对于指针的std::vector,@987654325 @ 将返回一个指向指针的指针。)

    另一个用于函数参数。对于函数参数,每个指针取值表示调用者可能会调用该函数,即使他们没有要传入的对象;然后他们可以传入NULL。 (否则为什么要使用指针而不是引用?请参阅 here 了解更多详情)。
    对指针进行非const 引用将表明被调用函数可能会为该指针分配一个新地址。
    因此,如果调用者传入一个指向它的指针,那么将指针指向指针将表明该函数可能会为指针分配一个新地址,但也可以使用NULL 调用。 例如:

    void f(int** ppi);
    void g(int i);
    
    void h()
    {
       f(NULL); // call `f()` only for its side-effects
    
       int* pi = NULL;
       f(&pi);  // call `f()` and get some object in *pi
       if(pi) 
         g(*pi); // use result
    }
    

    【讨论】:

      【解决方案4】:

      应在何处或何时使用指向指针的指针?

      在一个函数中,如果调用者请求,它可以选择返回指向调用者的指针。经常被系统 API、一些 COM 对象等使用。

      int f(void** p = 0){
          //.......
      }
      

      如果调用者提供了 p,那么函数通过 p 传递指针。如果调用者不提供 p,则不返回指针。在某些情况下可能对调试有用。

      有哪些好处?

      这个问题太宽泛了。看,这是一个非常简单的技术,没有什么神秘的好处。必要时使用它。就这样。这个概念没有隐藏的含义,也没有隐藏的优点——它相当于问“在英语中使用字母“e”有什么好处”。

      【讨论】:

      • +1 这太主流了,但很多其他答案都在说“你不应该这样做!”
      【解决方案5】:

      指向指针的指针在 C 中最相关。很少在 C++ 中需要它们。在那里,您可以使用标准库中的容器或引用。

      不过,C 中有两个流行的用例:

      1. 一个指针数组,最突出地用作 main() 的 argv:指针将地址提供给参数字符串数组(char* 类型)。在 C 中,[] 运算符作用于指向任何事物的指针,因为指向任何事物的指针被视为等同于数组。

      2. 一个函数参数,表示存储某物地址的位置。用例:在 C 语言中,返回值通常用于错误处理或状态信息。参数用于携带有效载荷。一个例子:一个函数将一个地址“返回”到新分配的内存,但使用一个参数。你给函数一个指针,指向之后应该指向数据的指针。该函数会覆盖该空间,为此,它需要一个指向指针的指针。

      【讨论】:

        【解决方案6】:

        您仅在使用手动内存管理时才使用它们,这在 C++ 中非常罕见,因此它们毫无用处。在大多数情况下,即使是常规指针的价值也值得怀疑。

        【讨论】:

          【解决方案7】:

          实际上有两个用例。

          首先,当您调用一个必须返回多个值的函数时,其中一些是指针。然后,你会为她提供一个指针的地址,这样它就可以填充指向的指针:

          int *p1 = 0, *p2 = 0, *p3 = 0;
          multi_malloc(&p1, &p2, &p3); // Allocates three pointers
          

          其次是当你想做稀疏的二维数组时:

          int main(int argc, char **argv)

          这是一个指向指针的指针。 argv[i] 是指向 char 的指针。这样,argv[i][j] 就是 i 行中的一个字符 j。

          您会很高兴听到指针对指针的使用几乎为零。 int ***p; 几乎没有用处。

          【讨论】:

          • 这是非常 C 语言。在 C++ 中,您可以引用指针,您可以用更简单(因此更不容易出错)的方式来使用它们。
          • 呵呵。 int ***p 看起来你审查了一些东西。
          • IIRC,根据 C++ 标准,您最多可以有 8 级取消引用。喜欢 int ********p
          • @Aamir:我很确定没有这样的限制。你有它的参考吗?
          猜你喜欢
          • 2012-10-07
          • 2022-11-11
          • 2018-04-22
          • 2020-07-20
          • 2011-12-16
          • 1970-01-01
          • 2013-06-27
          • 2021-07-07
          • 2021-12-04
          相关资源
          最近更新 更多