C++之引用和指针的区别

面试时被问到的一个问题,回答得不够全面,算是查漏补缺。

简述

我一直都有一个疑问,为什么在C++中有了指针还要引用?在Stroustrup: C++ Style and Technique FAQ中给出了回复,原文如下:

C++ inherited pointers from C, so I couldn’t remove them without causing serious compatibility problems. References are useful for several things, but the direct reason I introduced them in C++ was to support operator overloading.

翻译:C++中指针继承自C语言,出于兼容的原因保留了下来。引用的用处很多,但是C++引入它最直接的原因是为了支持运算符重载。

Read more

++i和i++的区别

简述

二者的区别本质上在于++i属于左值操作,而i++属于右值操作,可分以下几种情况分析:

Read more

《Effective Modern C++》条款24:区分万能引用和右值引用

简述

万能引用和右值引用都用”T&&“表示。

  • 万能引用

    所谓万能引用,即它既可以绑定左值,又可以绑定右值。一般用于表示型别推导的结果。

  • 右值引用

    右值引用,顾名思义就是只能绑定到右值,它的主要作用是作为可移动对象的标识。

Read more

《Effective Modern C++》条款23:理解std::move和std::forward

简述

  • std::move

    std::move,即移动语义。它的设计初衷在于让编译器用一种低成本的移动操作替换昂贵的复制操作。与之相关的两个函数分别是移动构造函数和移动赋值运算符。

    此外,std::move使得创建一个只可移动不可复制的对象成为可能,比如std::unique_ptr、std::future和std::thread等。

  • std::forward

    std::forward,即完美转发。它的设计初衷是使对任何一个函数模板,都可以将当前函数所接受的实参原封不动地转发给其它函数,且目标函数接受到的实参与传入当前函数的实参完全相同,包括实参的左右值属性。

  • 形参总是左值

    所谓左值,简单地说就是可寻址变量,而右值则是不可寻址的临时变量。

    1
    2
    3
    int a = 3;  // a是左值,3是右值
    a = a + 1; // 等号左边的a是右值,等号右边的a是右值
    // CPU取a的值存入临时变量,即寄存器,然后+1,再将寄存器的值赋值给a

    实参既可以是左值,也可以是右值。而形参总是左值,原因在于形参是为了传递实参的值或指针或引用而出现的,因此必须是可被赋值的左值。即便形参的类别是右值引用,如下:

    1
    void fun(Widget&& w);  // 形参w是一个左值
Read more

《Effective Modern C++》条款8:表示空指针优先选用nullptr,而非0或NULL

简述

  • 字面常量0的型别是int,而非指针。C++会在只能使用指针的语境中才勉强将其解释为空指针。

  • NULL是一个宏定义,而非指针。同样,C++会在只能使用指针的语境中才勉强将其解释为空指针。

    1
    2
    3
    4
    5
    6
    7
    8
    /* Define NULL pointer value */
    #ifndef NULL
    #ifdef __cplusplus
    #define NULL 0
    #else /* __cplusplus */
    #define NULL ((void *)0)
    #endif /* __cplusplus */
    #endif /* NULL */
  • nullptr是C++关键字,不具备整型型别。实际上,它也不具备指针型别,但是它可以隐式转换成任意指针型别,这也就是为什么nullptr可以用于初始化所有指针型别的原因。

Read more

《Effective Modern C++》条款10:优先选用enum class,而非enum

简述

众所周知,使用C++98中的枚举型别定义的枚举量,会泄漏到枚举型别所在的作用域中,这也意味着在此作用域内不能再有其他实体取相同的名称。因此,C++98中的枚举型别又称之为:不限作用域的枚举型别。

C++11为了解决这一问题,引入了限定作用域的枚举型别。由于限定作用域的枚举型别是通过”enum class“声明的,所以有时它们也被称为枚举类。

Read more