2017-03-17 49 views
4

代码A:让每个常量字符串都被引用是不是很好的做法?

string a = "Hello World"; 

for (int i=0; i<1000000; ++i) 
    const string b = a; 

代码B:

string a = "Hello World"; 

for (int i=0; i<1000000; ++i) 
    const string &b = a; 

如果我单独运行2点代码和测量CPU时间,所述代码B比代码A.快约2.5倍

不包括原始类型,如char,int,float ......我知道获得对原件的引用而不是复制它是更快的。

虽然差异在大多数情况下几乎可以忽略,但是可以考虑总是让const string类型(以及其他非原始类型)被引用吗?

+7

通常的指导原则如下。如果一个类型的sizeof大于sizeof(void *)',那么总是通过const引用传递,否则通过复制传递。如果您想更改对象,则传递非常量引用而不管大小。 – DeiDei

+2

也有例外 - 例如,如果您想在函数中创建参数的副本,然后按值传递 - 它会隐式地创建所需的副本,并且可以利用移动操作等功能来有效地执行此操作。 – jaggedSpire

+2

类可能会定义自定义复制或赋值操作符(如字符串),所以'sizeof'并不总是一个很好的复制时间指示器。 –

回答

3

是的,对于任何昂贵的复制对象,通常最好使用const引用。但是当你不期望它时,你必须小心原始物体不会改变;尤其是您需要确保原始对象不被破坏,因为这会导致未定义的行为。这不是玩具例子中的问题,但在现实世界中,这是一个大问题。

使用const引用的最佳位置是函数参数。你知道传入函数的对象在函数内部不能改变或被破坏。

2

有几件事要考虑。

  1. 您的用例。你想复制还是你想观察?
  2. 该类型是否执行深拷贝语义(例如,在拷贝上分配动态内存)?

如果你想仅仅观察物体
如果对象的类型分配上拷贝动态内存,则始终由常量引用传递。
否则,如果类型的sizeof大于sizeof(void*),则传递const引用。
否则按值传递。

如果您想复制对象,那么只需传递值。

当然,在一个奇怪的用例中,你可能会做其他的事情,但这是我通常遵循的一般指导原则。

还有移动语义要考虑,但这是一个不同的问题。

+2

你可能还想提一下'std :: string'有'std :: string_view'来观察C++ 17中的字符串。 – Rakete1111

+0

一个有趣的数据点是sizeof(string_view)'是关于'2 * sizeof(void *)'的,但'string_view'是通过C++ 17标准库中的值传递的。 –

+1

@BoPersson我最近在'libcxx'和'stdlibC++'中查看'std :: any'的实现。在'libcxx'中,他们认为一个“小对象”在'stdlibC++' - 'sizeof(void *)'中是'3 * sizeof(void *)'而不是。我发现这很有趣。它也可以在通过值传递的标准迭代器中找到。我的平台上的一些容器像'std :: deque'有一个大小为32字节的迭代器。 – DeiDei

相关问题