C ++函数:&符号和星号

时间:2009-03-21 22:15:47

标签: c++ function pointers

假设您有一个修改变量的函数。

你应该这样写:void myfunc(int *a)还是像这样void myfunc(int &a)

前者强制您使用myfunc(&b)调用该函数,以便调用者知道b将被修改,但后者更短,可以使用myfunc(b)简单调用。那么哪个更好用?还有其他我想念的东西吗?

9 个答案:

答案 0 :(得分:39)

指针(即'*')应该在传递“NULL”有意义的地方使用。 例如,您可以使用NULL来表示需要创建特定对象,或者不需要执行特定操作。 或者是否需要从非C ++代码调用它。 (例如,在共享库中使用)

例如。 libc函数time_t time (time_t *result);

如果result不为NULL,则将存储当前时间。但是如果result为NULL,则不执行任何操作。

如果您正在编写的函数不需要使用NULL作为有意义的值,那么使用引用(即'&')可能会减少混淆 - 假设这是您的项目使用的约定。

答案 1 :(得分:12)

我尽可能使用引用而不是指针。这样做的原因是,搞砸引用比指针更难。人们总是可以将NULL传递给指针值,但是没有这样的等价于引用。

唯一真正的缺点是C ++中的参考参数缺少呼叫站点文档。有些人认为这使得理解代码变得更加困难(我同意一定程度)。我通常在我的代码中定义以下内容并将其用于虚假的呼叫站点文档

#define byref
...
someFunc(byref x);

这当然不会强制执行呼叫站点文档。它只是提供了一种记录它的非常蹩脚的方式。我用模板进行了一些实验,该模板强制执行调用站点文档。尽管如此,这比实际生产代码更有趣。

http://blogs.msdn.com/jaredpar/archive/2008/04/03/reference-values-in-c.aspx

答案 2 :(得分:7)

我想我会不同意@bb和@JaredPar,我倾向于围栏的另一面。经过多年努力支持其他人的C ++代码,我经常发现潜在的参考参数的非明显副作用的问题。使用C#,很明显,因为你必须使用'ref'/'out'为参数类型添加前缀,但引用在C ++中可能会引起混淆。所以,我喜欢指针,因为很明显有些东西会重新出现。如果你不喜欢积分,那么C ++不适合你。

答案 3 :(得分:6)

由于这里和其他地方引用的原因,我来到围栏的指针一侧。但是,我会说,无论你决定什么,你都需要保持一致,并在你的风格指南中记录它。

Google C ++样式指南bans非const引用参数。

答案 4 :(得分:1)

  

前者迫使你打电话给   函数与myfunc(& b)一起调用   知道b将被修改

有时函数可以接受const指针,调用者会错误地认为b将被修改。

我的建议 - 更喜欢在任何可能的地方使用参考资料(当然需要它)。在功能参数的情况下 - 我们得到好处:
- 引用不能为NULL - 它有助于我们避免错误和不必要的断言或检查 - 引用只有一个初始化点,在函数boody中你总是知道输入参数指向什么东西。

我是大型项目的维护者。在任何一种情况下,我都会在调用它之前查看函数定义。当我查看函数定义时,我通过值,引用,const引用或指针看到参数定义。

但这似乎是圣战问题,不同的人在这一点上有不同的看法。例如。 google codding convension推荐在参数中使用指针,这些指针可以更改并且只允许const引用: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

  

所有通过引用传递的参数   必须标记为const。

答案 5 :(得分:1)

如果NULL没有意义,我喜欢通过引用传递,但我可以看到两者的参数。如果您对编码非常小心,可以通过确保始终通过const引用传递变量来消除意外的参考传递异议,例如:

myfunc( const_cast< const int& >( a ) );

// Alternatively, this approach may require additional handling 
// in the function, but it's cleaner at call point
myfunc( boost::cref( a ) );

但是这很多额外的代码几乎没有什么好处。正如Kenny指出的那样,C#从另一端解决了这个问题(需要通过引用进行特定的传递),但这不是C ++的一个选项(例如,除非您编写了函数以将引用包装器作为参数,例如boost :: ref(param)),例如:

void myfunc( const boost::reference_wrapper< int >& a ) { ... }

修复指针问题更有问题,但是......没有编译时方法来确保指针有效,因此最终会出现指针问题的运行时问题或运行时检查,或两者兼而有之。这是指针的本质。

无论如何,这只是我的意见,因为它的价值。

答案 6 :(得分:1)

需要注意的是,如果您使用的是stl仿函数,则参数与容器值类型匹配会更容易。

void foo(Bar *);

void frobnicate(vector<Bar *> vecBars)
{
   for_each(vecBars.begin(), 
            vecBars.end(), 
            ptr_fun(&foo));
}

如果foo采用Bar&amp;

,上面的代码会更难

答案 7 :(得分:0)

在理想的世界中,它取决于参数是否是可选输出。如果他们不关心它,你想让调用者传递NULL吗?然后使用指针。否则,参考是更好的选择。

请注意,在这两种情况下,语言都会使记录输出参数变得很麻烦。如果整个代码库是const正确的话会更好,那么用户可以假设任何非const引用或指针参数都是输出。

答案 8 :(得分:0)

之前提到的一个区别是,您无法传递空引用,但可以传递空指针。

另一件事,也是已经提到的,当你致电f(a,b)时,如果来电者不知道f可能会改变b

的价值,则可能会产生混淆

然而,另一个相当微妙的问题,但I still ran into it,是引用的语义。

指针按值传递,但引用不是。

这意味着,如果您通过指针传递参数,则可以更改指针并使其指向其他内容。

考虑一下:

void f1_ptr( type * a )
{
    a = new type(); //no change to passed parameters, you're changing the pointer which was passed by value
}

void f2_ptr( type * a )
{
    *a = some_other_value; //now you're changing the value of the parameter that was passed

   //or, if type is a class or struct:

   a->some_method_that_modifies_object(); //again, changing the parameter that was passed
}

但是,在通过引用传递时,您无法更改引用以引用其他值。设置参考后,就无法更改。

void f3_ref( type& a )
{
    a = type(); //the referred variable has also changed
}

//....

type obj = type( params );

f3_ref( obj ); //obj now changed

f1_ptr( &obj ); //obj doesn't change

f2_ptr( &obj ); //obj now changed