服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 一文让你彻底明白C++中的const

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

2021-10-06 13:14focuscode C/C++

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

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

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

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

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

?
1
2
3
4
5
6
7
void fun(int i, std::string const & str)
{
 i = 0;     //ok.
 str = "";    //error!
 int const n = 42;
 n = 2;     //error!
}

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

?
1
2
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`来改写:

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

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

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

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

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

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

?
1
2
3
4
5
6
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

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

?
1
2
3
4
5
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对象的声明,它有时可以使用其一致性进行优化。

?
1
2
3
4
5
6
7
8
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的对象。

?
1
2
3
4
5
6
7
8
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或其他整数值都可以像文字一样使用。

?
1
2
3
4
5
6
7
8
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变量。

?
1
2
3
4
5
6
7
8
9
10
11
12
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整数值超越界限,则它可能无法被当作字面常量使用,例如一下的例子。

?
1
2
3
4
5
6
7
8
9
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.

原文链接:https://mp.weixin.qq.com/s/ZyQ-56wcLaFp2qLyxCm-lQ

延伸 · 阅读

精彩推荐
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22