2012-08-13 46 views
12

在实际环境中,使用gcc或MS Visual Studio,通过const引用传递相同大小或小于int的值类型是不好的?在C++中,通过引用传递一个const布尔值是不是很好?

即是它坏写这样的功能:

void f(const bool& b); 

void f(const char& c); 

而非:

void f(bool b); 

void f(char c); 

我问的原因是我没有看到在这些情况下传递引用的好处,但也许我错过了一些东西。

+2

正如大多数人所说,没有任何意义,因为按价值传递这些信息可能会更快。但是,请记住,在这些微小的优化之前编写干净的代码,并且您可能有时会有几个非常相似的函数,它们会通过const引用接受参数,然后希望'bool'和'char'版本看起来一致。非常小的一点,但也许值得考虑,所以你不会让人们看着它思考“为什么这个不同?” – BoBTFish 2012-08-13 10:43:19

回答

15

可能稍差,否则它可能不会产生效果在所有(取决于在原始值存储,优化有多好,以及如何它决定处理你的代码)。

标准并不强制引用是如何被实现的,但在实践中的编译器使用指针实现引用。因此,在一般情况下,bool&将使用bool*实现,这意味着要访问bool,每次都需要额外的指针解引用。由于bool不比指针大,因此不会减少内存占用量或减少字节复制来弥补这一缺陷。

其结果是通行的做法是通过周围许多低级值,因为它的效率更高。当然,尽管通过引用并不会真的炸毁任何东西,除非你正在访问循环内的值,否则可能不会导致任何可测量的差异。

+0

当你写“由于bool不比指针大,所以不会减少内存占用量或减少字节复制来弥补这个缺点。”,实际上是一个布尔实际上比指针实际占用的空间更小,这取决于你是否将多个布尔值作为参数,导致通过引用传递使用更多的内存,或者是一个布尔采用相同的空间比int作为函数的参数? – BlueTrin 2012-08-13 11:03:54

+0

您可能会发现通过引用传递的基本类型(即'bool const&')的一种情况是在模板实例化中。除非明确针对所有基元类型,否则基元类型和更复杂的类型将使用相同的签名。 – 2012-08-13 11:05:28

+4

@BlueTrin:占用多少空间取决于体系结构中'sizeof(bool)'和'sizeof(bool *)'的值。传递每个参数的倍数不会改变图片。 – Jon 2012-08-13 11:32:04

-1

这其实并不重要,路过的价值,使你更干净的代码,因此被认为是很好的做法。

1

我觉得这是更好地传递内建类型by value而不是const reference,因为它几乎快。在通过引用传递的情况下,您需要创建一个引用(即获取地址),然后在使用该变量时解除引用。在大多数情况下,由编译器在任何情况下优化尽管

+1

只有在函数内联时才能优化它。无论你考虑*内联函数*大多数情况下*是否是一个不同的问题。 – 2012-08-13 10:57:24

2

其中一个原因是,你想传达给其他程序员的价值是恒定的,它可能在某些情况下更加清晰,尽管const bool就足够了。

+2

通过值传递使得函数不会修改调用者的值更加清晰。 – 2012-08-13 10:51:07

+0

通过const引用传递并不表示源是恒定的含义,只是它不会被函数修改(参见Björn的回答:函数外部的代码仍然可以更改该值)。另外,'const bool'作为参数根本不传达任何信息,因为在一个函数声明中,顶端的cv-qualifier被丢弃了(例如'void f(bool);'和'void f(const bool)'是完全相同的函数声明 – 2012-08-13 10:56:27

0

虽然理论上它不会是一个好主意,因为引用通常是使用指针实现的。但是,每个合理的编译器都应该足够聪明,以识别基本类型的by-const-reference和by-value之间的语义差异。

如果您有某种模板化界面必须适用于复杂类型和基本类型,并且您不希望过度专业化开销(最简单的示例:std::vector),那么通常您没有选择权。但是,如果你有选择,那么应该首选按值传递基本类型。

11

除了表现,实际上有些情况下你会得到不同的行为。

例如,传递const引用可确保函数不能更改被引用变量的值,但另一个线程可能会这样做。如果通过参考传递(即使使用const),您将看到这些更改,如果按值传递,则不会。

此外,界面的定义限制了您可以对函数内的变量执行的操作。考虑这个例子:如果你通过引用传递,你要修改本地使用的变量的值

int foo(int a) { 
    a = 5; // valid 
} 

int bar(const int& a) { 
    a = 5; // compiler-error 
} 

,你需要一个额外的副本。如果你通过价值传递,你已经有了一份副本。

+0

有关多线程环境的很好的一点 – BlueTrin 2012-08-13 10:52:34

+4

请注意,您并不需要多个线程来引用变量,例如'bool b(false); void f(const bool& a){assert(!a); b = true; assert(a);} int main(){f(b);}' – Mankarse 2012-08-13 11:15:20

+1

+1在不同地方(通过其他参考)提及对参数的可能更改。这也意味着由于可能的别名问题,某些优化将不会执行。 – 2012-08-13 11:41:13

相关问题