【问题标题】:Passing references to functions to be assigned to pointers in C++, Which way is better?传递对函数的引用以分配给 C++ 中的指针,哪种方式更好?
【发布时间】:2011-02-09 11:16:33
【问题描述】:

我想知道这两种将地址传递给指针的实现中哪一种更好。第一个中的数据交换在第二个中没有发生吗?第二种方法更有效吗?更具可读性?都一样吗?

版本 1

void ptrFunction(int& arg)
{
    int* ptr = &arg;
    std::cout<<"The pointer's value:" << *ptr << "\n";
}

int main()
{
    int  x=5;
    ptrFunction(x);
    return 0;
}

第 2 版

void CallViaPointers(int *arg)
{
  int *ptr = *arg;
  std::cout << "The pointer's value: " << *ptr;
}

int main()
{
    int x = 100;
    CallViaPointers(&x);
    return 0;
}

【问题讨论】:

  • 等等...这两个是等价的吗?
  • @muntoo:不,版本 1 中 x=5,版本 2 中 x=100 :)
  • @Øystein 哈哈。 :) 忽略这一点,版本 1 应该打印 5,但我不确定版本 2。
  • @muntoo:正如 Fred Nurk 所说,它有一个错字。

标签: c++


【解决方案1】:

就效率而言,两者几乎肯定会在幕后编译成相同的代码,因为引用通常被实现为自动取消引用的指针。从这个角度来看,这两种解决方案是等价的。

至于是通过指针传递还是通过引用传递,那真的是看情况的判断调用了。如果您要做的只是打印出指向整数的指针(就像您在此处所做的那样),那么按指针传递会更有意义,因为它更明确地与您尝试做的对齐.一般来说,编写函数,使参数是您内部想要的类型。如果你需要一个指针——要么是因为你正在构建一个链接结构,要么是因为你正在做某种内存分配——然后接受一个指针。如果您正在处理多态类,那么传统上您会通过指针而不是引用来接受您的参数,尽管两者都有效。如果您正在使用堆栈分配的对象来尝试修改它,那么引用可能会更清晰一些。而且,如果您处于必须使用引用的情况之一 - 例如,作为重载运算符、复制构造函数或赋值运算符的参数 - 那么当然要使用引用.如今,可读性确实被低估了,但努力编写干净、易读、直观的代码绝对值得。

【讨论】:

  • 我看到你最近给出了很多这样的答案。那些说“两者几乎肯定会编译成相同的代码”的人,停止尝试进行这种类型的微优化。他们都很优秀,这次也不例外。 +1
【解决方案2】:

性能方面,当然,这完全取决于实施。通常,它们将编译为相同的机器代码。这绝对是您根本不应该考虑优化的情况之一,除非您必须这样做。在大多数代码中,可读性更为重要。

至于可读性,我更喜欢版本 2,因为我希望我的函数的用户知道我将(或能够)修改他放入其中的任何内容,但这条规则有例外(例如在捕获异常或运算符重载时)。

【讨论】:

  • @Fred:我不喜欢一刀切的规则,有时我不得不牺牲可读性来换取性能。但是,是的,可读性几乎总是胜出。
【解决方案3】:

我会说这取决于函数的作用。 现在你的函数名与它的作用不符。如果是这样,它将被命名为 print_pointer 并且很明显它应该直接使用一个指针。(我读错了这个问题。但是,是的,它仍然取决于你的函数的作用。)

假设您有一个打印指针的函数,例如:

void print_pointer(void* ptr)
{
    std::cout << ptr << std::endl;
}

写这个函数来获取引用,然后获取它的地址是没有意义的,因为你不想要一个对象,你想要一个指向对象的指针,而null在this中是有效的上下文。

但是,如果您需要一个对象,就像您的代码一样,您应该获取一个引用,因为指向该对象是一个实现细节;带有引用的接口清楚地记录了您需要引用的对象。

就目前而言,第二版已损坏,因为传递 null 会使程序崩溃,但 null 是一个有效的指针值。如果不是这种情况,请不要宣传您想要一个指针值。要修复它,请检查 null 并做一些明确记录的事情,比如什么都不做或抛出异常。但最好将参数更改为引用,因为您将这些问题留给 调用者,而您的函数无论如何都可以工作。

(如果有人有一个指向对象的指针,他们可以负责安全地取消引用它以将有效对象传递给您的函数。换句话说,使用引用是自记录的:“null is not valid here” .)

性能无关紧要。

【讨论】:

    【解决方案4】:

    它们是等价的,这可以通过编译和检查反汇编来验证 - 除了符号名称之外,它们是相同的。

    至于风格,这主要是个人喜好,但有一种常见的模式是使用指针来表示外参数。这是因为当你引用一个引用时,不清楚你调用的函数是否会修改它。 “Effective C++”对入参使用 const 引用,对出参使用非常量指针。我发现这是明确合同内容的好方法。

    【讨论】:

    • 是的,除了 null,它作为参考无效。这是一个很少有用的属性,但至少在一个方面它们不是 100% 相同的。
    【解决方案5】:
    int *ptr = *arg;
    

    应该是:

    int *ptr = arg;
    

    当不清楚参数将用作其他地方的指针时,我发现引用参数比指针参数更具可读性。这通常是这种情况,并且参数的使用通常是封装的,因此调用者不关心实现细节。但是,您可能必须符合现有接口,并且可能使用指针作为迭代器 - 然后您“通过值传递迭代器”(传递迭代器的常用方法)而不是“传递指向对象的指针",即使该迭代器实际上是原始指针类型。 (其他类型的现有接口也是可能的。)

    除了以上个人偏好和一个允许空指针(不能有空引用)之外,它们在各个方面都是相同的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-14
      • 1970-01-01
      • 1970-01-01
      • 2013-11-14
      相关资源
      最近更新 更多