经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
使用constexpr时遇到的小坑
来源:cnblogs  作者:apocelipes  时间:2021/5/17 9:26:20  对本文有异议

最近在使用constexpr的时候无意中踩了个小坑。

下面给个小示例:

  1. #include <iostream>
  2. constexpr int n = 10;
  3. constexpr char *msg = "Hello, world!";
  4. int main()
  5. {
  6. for (auto i = 0; i < n; ++i) {
  7. std::cout << msg << std::endl;
  8. }
  9. }

constexpr应该是大家很熟悉的东西了,也是最常用的c++11新特性之一。和宏相比除了更强的类型安全之外,constexpr还带来了编译期计算。

上面的代码相当简单,我们循环输出“Hello, world!”这个字符串10次。

这么简单的代码还有讨论的必要吗?一开始我也是这么想的,然而当我们编译运行的时候却会得到下面这样的警告:

  1. $ g++ --version
  2. g++ (GCC) 10.2.0
  3. Copyright (C) 2020 Free Software Foundation, Inc.
  4. This is free software; see the source for copying conditions. There is NO
  5. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  6. $ g++ -std=c++17 -Wall -Wextra test.cpp
  7. test.cpp:4:23: 警告: ISO C++ forbids converting a string constant to char*’ [-Wwrite-strings]
  8. 4 | constexpr char *msg = "Hello, world!";
  9. | ^~~~~~~~~~~~~~~

这段信息的意思是c++不允许把字符串字面量赋值给char*

然而对于constexpr,文档中是这么写的:

A constexpr specifier used in an object declaration implies const.

这里的object你可以理解为变量,意思是constexpr修饰的变量都会隐式添加一个const限定符。

也就是说:

  1. // T 是任意类型
  2. constexpr T a = xxx;
  3. // 不考虑其他因素,在类型上等价于:
  4. T const a = xxx;

我们这里的T实际上可以填任意类型,包括指针。这不是说明我们的指针变量有const吗?

眼尖的读者大概已经知道答案了:constexpr添加的是顶层const。

所以我们的代码实际上是这样的:

  1. // 原本的代码
  2. constexpr char *msg = "Hello, world!";
  3. // 实际上的效果
  4. char * const msg = "Hello, world!";

下面一行的msg实际上是一个指向char的指针常量,而我们可以通过它任意修改被指向的字符串(当然这是未定义行为)。指针常量意味着我们不能把这个指针重新指向其他的对象,这个const作用在指针本身上,因此叫做顶层const。

而字符串常量的类型是const char[N],在表达式里退化为const char *,这表示一个指向常量字符串的指针,这里的const的底层的,因为它作用于被指向的对象而不是我们的指针自身。

对于顶层const,赋值的时候是可以被去除的,而底层const则不行,这就是为什么编译器会弹出警告的原因了。

正确的做法也很简单,牢记constexpr不是const的等价替代品,它只会添加顶层const,不会添加底层const。

所以constexpr的字符串常量应该这样写:

  1. constexpr const char *p = "Hello, world!";

或者你的编译环境支持c++17,我更推荐你这样写:

  1. #include <string_view>
  2. constexpr std::string_view msg = "Hello, world!";

使用string_view之后就不会出现上面的顶层/底层const的坑了。所以在现代c++里能不用裸指针就尽量不要用。

参考

https://stackoverflow.com/questions/54258241/warning-iso-c-forbids-converting-a-string-constant-to-char-for-a-static-c

原文链接:http://www.cnblogs.com/apocelipes/p/14769971.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号