一文让你彻底明白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.

相关文章

  • C语言实现线索二叉树的定义与遍历示例

    C语言实现线索二叉树的定义与遍历示例

    这篇文章主要介绍了C语言实现线索二叉树的定义与遍历,结合具体实例形式分析了基于C语言的线索二叉树定义及遍历操作相关实现技巧与注意事项,需要的朋友可以参考下
    2017-06-06
  • C++实现正态随机分布的方法

    C++实现正态随机分布的方法

    本篇介绍了,使用c++实现正态随机分布的实现方法。需要的朋友参考下
    2013-05-05
  • opencv学习笔记C++绘制灰度直方图

    opencv学习笔记C++绘制灰度直方图

    这篇文章主要为大家介绍了opencv学习笔记C++绘制灰度直方图的实现代码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • C语言中定义与声明有哪些区别

    C语言中定义与声明有哪些区别

    在C/C++中有一个基础且重要的知识,什么是声明?什么是定义?他们的区别是什么?本文将带你理清其中的区别
    2022-07-07
  • 详解C++设计模式编程中策略模式的优缺点及实现

    详解C++设计模式编程中策略模式的优缺点及实现

    这篇文章主要介绍了C++设计模式编程中策略模式的优缺点及实现,文中讨论了策略模式中设计抽象接口的继承和组合之间的区别,需要的朋友可以参考下
    2016-03-03
  • C语言用函数实现反弹球消砖块

    C语言用函数实现反弹球消砖块

    这篇文章主要为大家详细介绍了C语言用函数实现反弹球消砖块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C语言之二叉树的遍历

    C语言之二叉树的遍历

    这篇文章主要介绍了C语言中二叉树的遍历:前序、中序、后序,认识二叉树结构最简单的方式就是遍历二叉树,感兴趣的小伙伴可以参考阅读本文
    2023-03-03
  • 纯c实现异常捕获try-catch组件教程示例

    纯c实现异常捕获try-catch组件教程示例

    这篇文章主要为大家介绍了纯c实现异常捕获try-catch组件教程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Visual studio2022 利用glfw+glad配置OpenGL环境的详细过程

    Visual studio2022 利用glfw+glad配置OpenGL环境的详细过程

    这篇文章主要介绍了Visual studio2022 利用glfw+glad配置OpenGL环境,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • C语言实现猜数字小游戏的示例代码

    C语言实现猜数字小游戏的示例代码

    猜数字小游戏是我们小时候喜欢我们一个经典小游戏。这篇文章将利用C语言中的循环语句、分支语句和函数实现这一游戏,需要的可以参考一下
    2022-10-10

最新评论