English 中文(简体)
通过引用调用vs指针参数[重复]
原标题:Call by reference vs Pointer argument [duplicate]
  • 时间:2011-02-16 08:21:09
  •  标签:
  • c++
This question already has answers here:
Closed 12 years ago.

Possible Duplicate:
FAQ: How to pass objects to functions in C++?
Pointer vs. Reference

Hi all,
in c/c++, we can pass a object as call by reference or passing pointer of the object.
for example:
i want to create a function which will take string vector as input and output a map that contains some value for each string. the return value of the function is bool, which indicate success or failure.

函数(通过引用调用)

bool calculateSomeValue( vector<string> input, map<string, double>& result)
{
//// bla bla bla
return true/false;
}

函数(使用指针)

bool calculateSomeValue( vector<string> input, map<string, double>* result)
{
//// bla bla bla
return true/false;
}

哪一个最好?有人知道这两种选择的利弊吗?

提前谢谢。

最佳回答

这是一个风格问题。在谷歌(请参阅Google C++风格的指导方针),以下是首选:

bool CalculateSomeValue(
    const vector<string>& input, map<string, double>* result);

这是因为使用指针需要在调用位置显式使用“与”符号:

 CalculateSomeValue(input, &result);

与使用引用类型调用它的方式相反:

 CalculateSomeValue(input, result);

在修改参数的情况下,通过强制使用“与”符号,可以在调用站点清楚地看到会发生什么。当使用引用时,有必要查找每个函数的文档,以了解它是否有可能修改其输入参数。

然而,使用指针也有其缺点。特别是,指针的使用意味着将处理null的责任从指针将被取消引用的调用方(如果变量是指针,而不仅仅是带有局部变量的表达式的地址)转移到函数。也就是说,当使用指针类型时,CalculateSomeValue需要检查nullptr(或者需要清楚地记录它需要在调用方中进行此检查),而引用类型的使用是自记录的,并且清楚地表明应使用非null引用。

对于这种特殊情况,我个人强烈建议采用混合方法:

bool CalculateSomeValue(
   const std::vector<std::string>& input,
   Output<map<string, double>> result);

…其中输出<;T>是由一个具有签名的函数创建的:

 template<typename T> Output<T> WriteTo(T& output_ref);

…并且其中<code>输出<;T>重载运算符->*等。这基本上迫使调用站点明确输入将通过以下要求进行变异:

 CalculateSomeValue(input, WriteTo(result));

…而不是:

 CalculateSomeValue(input, result);

…同时获得引用的非null语义/语法。

问题回答

如果这个参数不是可选的,我发现c++许多开发人员更喜欢通过引用传递。然而,许多人喜欢只为视觉提示而传递指针。这有点像c的遗留问题,随着程序的发展,它会随着引用和指针的混合使用而受到侵蚀。

您可以假设引用不是null,但对于指针,您不应该这样认为。在这种情况下,你必须引入先决条件脚手架/检查,以确保上游的人不认为这个论点是可选的——如果你是防御性的。

就我个人而言,我更喜欢通过引用传递,并使用描述性方法/函数/变量名(如果你只详细说明标签,那么人们必须更频繁地查看文档)。这使程序的意图保持清晰,并避免了额外的书面检查get*update*可能比calcult*

使用引用是一致的、定义良好的,并且生成更简单的程序,因为您不处理混合的变量/参数类型。

在这种情况下,您选择哪一个并没有什么显著的区别,只是在您的使用中保持一致。我使用的另一个提示是将修改后的参数放在相同的位置。具体来说,它们位于常量参数之前。

bool calculateSomeValue( vector<string> input, map<string, double>&* result)

指向引用的指针?这甚至不会编译。第一个是正确的,只有正确的才是最好的!

struct A {};

void f(A & *a) {}

编译时出现错误:

prog.cpp:7: error: cannot declare pointer to ‘struct A&’

Ideone示例:http://www.ideone.com/8PJA5

您的第二个代码示例似乎不正确,因为您试图接受指向引用的指针,而该引用不应该编译。

通过引用传递和传递指针同样有效(如果我错了,有人会纠正我,但我的理解是,引用本质上是一个自动创建的指针,然后无缝地取消引用),但建议通过引用传递,因为这样更安全:

  • You cannot have a null reference.
  • You can t change the address referenced, whereas a pointer would allow you to.

有些人更喜欢显式指针语法,它清楚地表明它是指向传入对象的指针(因为必须取消引用)。

最好的解决方案并不存在。这是一个又一个案例。

例如,在某些情况下,next可能会更好:

map<string, double> calculateSomeValue( const vector<string> &input )
{
  map<string, double> res;
// do something with input to form the output
  return res;
}

但是,如果可以的话,更喜欢使用标准算法

我假设第二个应该只是通过点,而不是指向引用的指针。

两者之间的决定只是风格和品味的问题。两行的编译结果可能是相同的。

通常对于输出参数,C++风格的指南说应该通过指针。

使用引用的唯一时间是在实现需要引用的标准运算符时。

然而,除此之外,对于任何应用程序方法,指针应该始终优先于引用。

  • 用户对象经常存储在指针中,无论是智能的还是其他的。当按需创建对象时,对引用始终有效的约束过于严格。这使得引用参数不方便使用,因为需要进行笨拙的操作来传递值<代码>引用函数((*pObj))

  • 通过引用传递是试图实现契约范式的廉价替代品。c++不支持。

  • 对该传递引用的所有(*somePtr)操作都意味着你无论如何都会得到要调试的空指针,只是更模糊,因为空指针看起来不像指针。

  • 当程序员无法通过简单的检查来判断函数的哪些参数可能会更改时,决不要忘记维护问题。





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?