一文让你彻底明白C++中的const

 更新时间:2020年11月17日 14:53:54   作者:focuscode  
这篇文章主要给大家介绍了关于C++中const的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在抽象的最高层次上,const做两件事:

* 一种保护你自己的方式(类似于private)

* 对编译器的一种指示,表明标记为const的对象适合于程序的数据段。换句话说,属于只读数据(ROM-able)。

可以通过例子来看下const的应用。第一个例子中,使用const覆盖了整个例子:

void fun(int i, std::string const & str)
{
 i = 0;     //ok.
 str = "";    //error!
 int const n = 42;
 n = 2;     //error!
}

第二种情况只适用于静态初始化的名称空间-作用域变量(又称全局变量):

int const pi = 3; //ROM-able
std::vector<int> const ivec = {/* ... */}; //Not ROM-able, might allocate.

对声明为const的变量的任何写操作都被显示为未定义行为。这支持const全局变量在ROM中的位置。

如果一个变量定义在ROM中,对它的写操作很可能会使程序崩溃,这取决于平台。如果一个变量不在ROM中,对它的写操作只会改变它的值。这两种情况的结合就是为什么对const变量执行写操作的行为是未定义行为而不是错误。

如果真的需要改写一个const变量的值,可以通过`const_cast`来改写:

void fun(int i, std::string const & str)
{
 i = 0; //ok.
 const_cast<std::string &>(str) = ""; //Also ok (maybe).
}

然而,const_cast并不能避免你在尝试写入声明为const的变量时永远不会遭遇未定义行为的陷阱。

std::string str = "";
fun(0, str); // Ok.
std::string const const_str = "";
fun(0, const_str); // Undefined Behavior!!

因此,只有在确实需要时才使用const_cast,并且只有在知道要写入的底层变量是如何声明的情况下才使用。

**那么,究竟在什么时候什么地方使用const?**

答案就是**Everywhere**。将每个变量声明为const,除非您知道它将被写入。更一般地,在编译器接受的任何地方添加const。

int foo(int arg)
{
 int const x = compute_intermediate_result(arg);
 int const y = compute_other_intermediate_result(x);
 return something_computed_from(x, y);
}

优化器视角下的const

为了优化目的,编译器通常不能使用一致性进行优化。

int get_value(some_class const & x, int const at)
{
 int offset = compute_offset(at);
 return x[offset];
}

此时,在这些函数参数中使用const对优化器没有帮助。x上的const不起作用,因为x已经通过引用传递了。没有x的副本,编译器不知道x是否声明为const。在参数at上的const不能帮助我们,因为at是一个拷贝,它可以以任何方式装入寄存器。
如果编译器可以看到const对象的声明,它有时可以使用其一致性进行优化。

std::vector<int> const vec = { 1, 2, 3 };

int main()
{
 // This may generate code that indexes into vec, or it may generate
 // code that loads an immediate 2.
 return vec[1];
}

如果您想保证这样的优化,您可以在c++11或以后的版本中使用constexpr。使用constexpr声明的变量只对可以静态初始化的类型进行编译,因此,如果编译了它,就会得到一个ROM-able的对象。

constexpr std::array<int, 3> arr = { 1, 2, 3 };

int main()
{
 // This generates code that loads an immediate 2 on every
 // compiler I tried.
 return arr[1];
}

constexpr只处理字面常量类型(literal types)。这些类型与你可能在C中找到的类型相似。任何被声明为const的int或其他整数值都可以像文字一样使用。

void foo(int const arg)
{
 int const size = 2; 

 int array_0[2];  // Ok.
 int array_1[arg]; // Error! arg is a runtime value.
 int array_2[size]; // Ok.
}

静态const类成员

如果声明一个类成员static const,就很像声明一个全局const变量。

int const global_size = 3;

struct my_struct
{
 static int const size = 2;
};

std::array<int, global_size> make_global_array()
{ return {}; }

std::array<int, my_struct::size> make_my_struct_array()
{ return {}; }

但因为这是c++,所以有个问题。如果定义的static const整数值超越界限,则它可能无法被当作字面常量使用,例如一下的例子。

struct my_struct
{
 static int const size;
};

std::array<int, my_struct::size> make_my_struct_array() // Error!
{ return {}; }

int const my_struct::size = 2;

这是的错误时因为编译器在解析foo()时不知道要为my_class::size使用什么值。如果你希望像使用全局const整数值一样使用static const整数值,请始终将它们声明为内联(inline)。

总结

到此这篇关于C++中const的文章就介绍到这了,更多相关C++中的const内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

1. Use const to protect yourself from silly mistakes, and use it everywhere.

2. You can use const on globals that you want in ROM, but prefer constexpr.

3. Use const_cast sparingly, or not at all.

4. When you do use const_cast, be careful of the UB that might result, including crashes.

5. Use const globals and stack variables instead of macros for named values that are "as good as literals".

6. Define static const integral data members inline, if possible.

相关文章

  • ubuntu中打开终端的三种解决方法

    ubuntu中打开终端的三种解决方法

    本篇文章是对ubuntu中打开终端的三种方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 利用c++和easyx图形库做一个低配版扫雷游戏

    利用c++和easyx图形库做一个低配版扫雷游戏

    这篇文章主要介绍了用c++和easyx图形库做一个低配版扫雷游戏,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01
  • C语言for语句用法详解

    C语言for语句用法详解

    今天,小编讲诉C语言中循环语句(for)的使用方法,作为示例,以一个简单的例子讲诉for语法。
    2015-11-11
  • C++多线程std::call_once的使用

    C++多线程std::call_once的使用

    本文主要介绍了C++多线程std::call_once的使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Windows环境给FFmpeg集成AVS3解码器

    Windows环境给FFmpeg集成AVS3解码器

    libuavs3d是AVS3标准的解码器,支持windows/linux/arm/ios等所有常用平台,在移动端最高支持4K/30fps视频实时解码,解码速度大幅领先AV1开源解码器dav1d和aomdec,由于FFmpeg默认未启用libuavs3d,因此需要重新配置FFmpeg,标明启用libuavs3d,然后重新编译安装FFmpeg
    2024-05-05
  • 浅谈c++调用python链接的问题及解决方法

    浅谈c++调用python链接的问题及解决方法

    下面小编就为大家带来一篇浅谈c++调用python链接的问题及解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • C++中malloc与free、new与delete的详解与应用

    C++中malloc与free、new与delete的详解与应用

    今天小编就为大家分享一篇关于C++中malloc与free、new与delete的详解与应用,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 基于Qt的TCP实现通信

    基于Qt的TCP实现通信

    这篇文章主要为大家详细介绍了基于Qt的TCP实现通信,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C语言strtod()函数案例详解

    C语言strtod()函数案例详解

    这篇文章主要介绍了C语言strtod()函数案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++中 string 中的常用方法使用心得

    C++中 string 中的常用方法使用心得

    这篇文章主要介绍了C++中 string 中的常用方法使用心得,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03

最新评论