C++中逻辑Const和物理Const

Rockchip RK3568实战:手把手教你调试I2S音频驱动(附ALSA设备树配置详解) 本文提供Rockchip RK3568平台I2S音频驱动的实战调试指南。详细解析了从硬件连接到软件配置的全过程,重点涵盖ALSA驱动框架下的设备树配置、时钟计算、DMA参数设置以及常见问题(如无声、爆音)的排查与解决方法,帮助开发者快速定位并解决音频驱动难题。 阅读详情

只要可能就用const

关于 const 的一件美妙的事情是它允许你指定一种语义上的约束:一个特定的对象不应该被修改。而编译器将执行这一约束。它允许你通知编译器和其他程序员,某个值应该保持不变。如果确实如此,你就应该明确地表示出来,因为这样一来,你就可以谋取编译器的帮助,确定这个值不会被改变。

  关键字 const 非常多才多艺。在类的外部,你可以将它用于全局常量或命名空间常量,就像那些在文件、函数或模块范围内被声明为 static 的对象。在类的内部,你可以将它用于 static 和 non-static 数据成员上。对于指针,你可以指定这个指针本身是 const,或者它所指向的数据是 const,或者两者都是,或者都不是。

char greeting[] = "Hello";

char *p = greeting; // non-const pointer,
// non-const data

const char *p = greeting; // non-const pointer,
// const data

char * const p = greeting; // const pointer,
// non-const data

const char * const p = greeting; // const pointer,
// const data

  这样的语法本身其实并不像表面上那样反复无常。如果 const 出现在 * 左边,则指针指向的内容为常量;如果 const 出现在 * 右边,则指针自身为常量;如果 const 出现在 * 两边,则两者都为常量。

  当指针指向的内容为常量时,一些人将 const 放在类型之前,另一些人将 const 放在类型之后 * 之前。两者在意义上并没有区别,所以,如下两个函数具有相同的参数类型:

void f1(const Widget *pw); // f1 takes a pointer to a
// constant Widget object

void f2(Widget const *pw); // so does f2

  因为它们都存在于实际的代码中,你应该习惯于这两种形式。

  STL iterators 以指针为原型,所以一个 iterator 在行为上非常类似于一个 T* 指针。声明一个 iterator 为 const 就类似于声明一个指针为 const(也就是说声明一个 T* const 指针):不能将 iterator 指向另外一件不同的东西,但是它所指向的东西本身可以变化。如果你要一个 iterator 指向一个不能变化的东西(也就是 const T* 的 STL 对等物),你应该用 const_iterator:

std::vector<int> vec;
...
const std::vector<int>::iterator iter = // iter acts like a T* const

vec.begin();

*iter = 10; // OK, changes what iter points to

++iter; // error! iter is const

std::vector<int>::const_iterator cIter = //cIter acts like a const T*

vec.begin();

*cIter = 10; // error! *cIter is const

++cIter; // fine, changes cIter

  对 const 最强有力的用法来自于它在函数声明中的应用。在一个函数声明中,const 既可以用在函数返回值上,也可以用在个别的参数上,对于成员函数,还可以用于整个函数。

  一个函数返回一个常量,常常可以在不放弃安全和效率的前提下尽可能减少客户的错误造成的影响。例如,考虑在 Item 24 中考察的 rational 成员 operator* 的声明:

class Rational { ... };

const Rational operator*(const Rational& lhs, const Rational& rhs);

  很多第一次看到这些的人会不以为然。为什么 operator* 的结果应该是一个 const 对象?因为如果它不是,客户就可以犯下如此暴行:

Rational a, b, c;
...
(a * b) = c; // invoke operator= on the
// result of a*b!

  我不知道为什么一些程序员要为两个数的乘积赋值,但是我知道很多程序员这样做也并非不称职。所有这些可能来自一个简单的输入错误(要求这个类型能够隐式转型到 bool):

if (a * b = c) ... // oops, meant to do a comparison!

  如果 a 和 b 是内建类型,这样的代码显而易见是非法的。一个好的用户自定义类型的特点就是要避免与内建类型毫无理由的不和谐,而且对我来说允许给两个数的乘积赋值看上去正是毫无理由的。将 operator* 的返回值声明为 const 就可以避免这一点,这就是我们要这样做的理由。

  关于 const 参数没什么特别新鲜之处——它们的行为就像局部的 const 对象,而且无论何时,只要你能,你就应该这样使用。除非你需要改变一个参数或本地对象的能力,否则,确认将它声明为 const。它只需要你键入六个字符,就能将你从我们刚刚看到的这个恼人的错误中拯救出来:“我想键入‘==’,但我意外地键入了‘=’”。

  const 成员函数

  成员函数被声明为 const 的目的是确信这个函数可能会被 const 对象调用。因为两个原因,这样的成员函数非常重要。首先,它使一个类的接口更容易被理解。知道哪个函数可以改变对象而哪个不可以是很重要的。第二,它们可以和 const 对象一起工作。书写高效代码有一个很重要的方面,就像 Item 20 所解释的,提升一个 C++ 程序的性能的基本方法就是就是传递一个对象的引用给一个 const 参数。这个技术只有在 const 候选对象有 const 成员函数可操作时才是可用的。

  很多人没有注意到这样的事实,即成员函数只有常量性不同时是可以被重载的,这是 C++ 的一个重要特性。考虑一个代表文字块的类:

class TextBlock {

 public:
  ...
  const char& operator[](std::size_t position) const // operator[] for
  { return text[position]; } // const objects
  char& operator[](std::size_t position) // operator[] for
  { return text[position]; } // non-const objects
 private:
  std::string text;
};
 

  TextBlock 的 operator[]s 可能会这样使用:

TextBlock tb("Hello");

std::cout << tb[0]; // calls non-const
// TextBlock::operator[]

const TextBlock ctb("World");

std::cout << ctb[0]; // calls const TextBlock::operator[] 

  顺便提一下,const 对象在实际程序中最经常使用的是作为这样一个操作的结果:将指针或者引用传递给 const 参数。上面的 ctb 的例子是人工假造的。下面这个例子更真实一些:

void print(const TextBlock& ctb) // in this function, ctb is const
{
 std::cout << ctb[0]; // calls const TextBlock::operator[]
 ...
}

  通过将 operator[] 重载,而且给不同的版本不同的返回类型,你能对 const 和 non-const 的 TextBlocks 做不同的操作:

std::cout << tb[0]; // fine - reading a
// non-const TextBlock

tb[0] = ’x’; // fine - writing a
// non-const TextBlock

std::cout << ctb[0]; // fine - reading a
// const TextBlock

ctb[0] = ’x’; // error! - writing a
// const TextBlock

  请注意这个错误只是发生在调用 operator[] 的返回类型上,而调用 operator[] 本身总是正确的。错误出现在企图为 const char& 赋值的时候,而这正是 const 版本的 operator[] 的返回类型。

  再请注意 non-const 版本的 operator[] 的返回类型是一个字符的引用而不是字符本身。如果 operator[] 只是简单地返回一个字符,下面的语句将无法编译:

tb[0] = ’x’;

  因为改变一个返回内建类型的函数的返回值总是非法的。如果它合法,那么 C++ 以值(by value)返回对象这一事实(参见 Item 20)就意味着 tb.text[0] 的副本被改变,而不是 tb.text[0] 自己,这不会是你想要的行为。

  让我们为哲学留一点时间。看看一个成员函数是 const 意味着什么?有两个主要的概念:二进制位常量性(bitwise constness)(也称为物理常量性(physical constness))和逻辑常量性(logical constness)。

  二进制位 const 派别坚持认为,一个成员函数,当且仅当它不能改变对象的任何数据成员(static 成员除外),也就是说不能改变对象内的任何二进制位,则这个成员函数就是 const。二进制位常量性的一个好处是比较容易监测违例:编译器只需要寻找对数据成员的赋值。实际上,二进制位常量性就是 C++ 对常量性的定义,一个 const 成员函数不被允许改变调用它的对象的任何 non-static 数据成员。

  不幸的事,很多成员函数并不能完全通过二进制位常量性的检验。特别是,一个经常改变一个指针指向的内容的成员函数。除非这个指针在这个对象中,否则这个函数就是二进制位 const 的,编译器也不会提出异议。例如,假设我们有一个类似 TextBlock 的类,因为它需要与一个不知 string 为何物的 C API 打交道,所以它需要将它的数据存储为 char* 而不是 string。

class CTextBlock {
 public:
  ...
  char& operator[](std::size_t position) const // inappropriate (but bitwise

  { return pText[position]; } // const) declaration of
  // operator[]
 private:
  char *pText;
};

  尽管 operator[] 返回对象内部数据的引用,这个类还是(不适当地)将它声明为 const 成员函数(Item 28 将谈论一个深入的主题)。先将它放到一边,看看 operator[] 的实现,它并没有使用任何手段改变 pText。结果,编译器愉快地生成了 operator[] 的代码,因为对所有编译器而言,它都是二进制位 const 的,但是我们看看会发生什么:

const CTextBlock cctb("Hello"); // declare constant object

char *pc = &cctb[0]; // call the const operator[] to get a
// pointer to cctb’s data

*pc = ’J’; // cctb now has the value "Jello"

  这里确实出了问题,你用一个确定的值创建一个常量对象,然后你只是用它调用了 const 成员函数,但是你改变了它的值! 这就引出了逻辑常量性的概念。这一理论的信徒认为:一个 const 成员函数被调用的时候可能会改变对象中的一些二进制位,但是只能用客户无法感觉到的方法。例如,你的 CTextBlock 类在需要的时候可以储存文字块的长度:

class CTextBlock {
 public:
  ..
  std::size_t length() const;

 private:
  char *pText;
  std::size_t textLength; // last calculated length of textblock
  bool lengthIsValid; // whether length is currently valid
};

std::size_t CTextBlock::length() const
{
 if (!lengthIsValid) {
  textLength = std::strlen(pText); // error! can’t assign to textLength
  lengthIsValid = true; // and lengthIsValid in a const
 } // member function
 return textLength;
}

  length 的实现当然不是二进制位 const 的—— textLength 和 lengthIsValid 都可能会被改变——但是它还是被看作对 const CTextBlock 对象有效。但编译器不同意,它还是坚持二进制位常量性,怎么办呢?

  解决方法很简单:利用以关键字 mutable 为表现形式的 C++ 的 const-related 的灵活空间。mutable 将 non-static 数据成员从二进制位常量性的约束中解放出来:

class CTextBlock {
 public:
  ...
  std::size_t length() const;

 private:
  char *pText;
  mutable std::size_t textLength; // these data members may
  mutable bool lengthIsValid; // always be modified, even in
}; // const member functions

std::size_t CTextBlock::length() const
{
 if (!lengthIsValid) {
  textLength = std::strlen(pText); // now fine
  lengthIsValid = true; // also fine
 }
 return textLength;
}

避免 const 和 non-const 成员函数的重复

  mutable 对于解决二进制位常量性不太合我的心意的问题是一个不错的解决方案,但它不能解决全部的 const-related 难题。例如,假设 TextBlock(包括 CTextBlock)中的 operator[] 不仅要返回一个适当的字符的引用,它还要进行边界检查,记录访问信息,甚至数据完整性确认,将这些功能加入到 const 和 non-const 的 operator[] 函数中,使它们变成如下这样的庞然大物:

class TextBlock {
 public:
  ..
  const char& operator[](std::size_t position) const
  {
   ... // do bounds checking
   ... // log access data
   ... // verify data integrity
   return text[position];
  }
  char& operator[](std::size_t position)
  {
   ... // do bounds checking
   ... // log access data
   ... // verify data integrity
   return text[position];
  }
 private:
  std::string text;
};

  哎呀!你是说重复代码?还有随之而来的额外的编译时间,维护成本以及代码膨胀等令人头痛的事情吗?当然,也可以将边界检查等全部代码转移到一个单独的成员函数(当然是私有的)中,并让两个版本的 operator[] 来调用它,但是,你还是要重复写出调用那个函数和返回语句的代码。

  怎样才能只实现一次 operator[] 功能,又可以使用两次呢?你可以用一个版本的 operator[] 去调用另一个版本。并通过强制转型去掉常量性。

  作为一个通用规则,强制转型是一个非常坏的主意,我将投入整个一个 Item 来告诉你不要使用它,但是重复代码也不是什么好事。在当前情况下,const 版本的 operator[] 所做的事也正是 non-const 版本所做的,仅有的不同是它有一个 const 返回类型。在这种情况下,通过转型去掉返回类型的常量性是安全的,因为,无论谁调用 non-const operator[],首要条件是有一个 non-const 对象。否则,他不可能调用一个 non-const 函数。所以,即使需要一个强制转型,让 non-const operator[] 调用 const 版本以避免重复代码的方法也是安全的。代码如下,随后的解释可能会让你对它的理解更加清晰:

class TextBlock {
 public:
  ...
  const char& operator[](std::size_t position) const // same as before
  {
   ...
   ...
   ...
   return text[position];
  }
  char& operator[](std::size_t position) // now just calls const op[]
  {
   return
   const_cast<char&>( // cast away const on
   // op[]’s return type;
   static_cast<const TextBlock&>(*this) // add const to *this’s type;
   [position] // call const version of op[]
  );
 }
 ...
};

  正如你看到的,代码中有两处强制转型,而不止一处。我们让 non-const operator[] 调用 const 版本,但是,如果在 non-const operator[] 的内部,我们仅仅调用了 operator[],那我们将递归调用我们自己一百万次甚至更多。为了避免无限递归,我们必须明确指出我们要调用 const operator[],但是没有直接的办法能做到这一点,于是我们将 *this 从它本来的类型 TextBlock& 强制转型到 const TextBlock&。是的,我们使用强制转型为它加上了 const!所以我们有两次强制转型:第一次是为 *this 加上 const(目的是当我们调用 operator[] 时调用的是 const 版本),第二次是从 const operator[] 的返回值之中去掉 const。

  增加 const 的强制转型是一次安全的转换(从一个 non-const 对象到一个 const 对象),所以我们用 static_cast 来做。去掉 const 的强制转型可以用 const_cast 来完成,在这里我们没有别的选择。

  在完成其它事情的基础上,我们在此例中调用了一个操作符,所以,语法看上去有些奇怪。导致其不会赢得选美比赛,但是它通过在 const 版本的 operator[] 之上实现其 non-const 版本而避免重复代码的方法达到了预期的效果。使用丑陋的语法达到目标是否值得最好由你自己决定,但是这种在一个 const 成员函数的基础上实现它的 non-const 版本的技术却非常值得掌握。

  更加值得知道的是做这件事的反向方法——通过用 const 版本调用 non-const 版本来避免代码重复——是你不能做的。记住,一个 const 成员函数承诺不会改变它的对象的逻辑状态,但是一个 non-const 成员函数不会做这样的承诺。如果你从一个 const 成员函数调用一个 non-const 成员函数,你将面临你承诺不会变化的对象被改变的风险。这就是为什么使用一个 const 成员函数调用一个 non-const 成员函数是错误的,对象可能会被改变。实际上,那样的代码如果想通过编译,你必须用一个 const_cast 来去掉 *this 的 const,这样做是一个显而易见的麻烦。而反向的调用——就像我在上面的例子中用的——是安全的:一个 non-const 成员函数对一个对象能够为所欲为,所以调用一个 const 成员函数也没有任何风险。这就是 static_cast 可以在这里工作的原因:这里没有 const-related 危险。

  就像在本文开始我所说的,const 是一件美妙的东西。在指针和迭代器上,在涉及对象的指针,迭代器和引用上,在函数参数和返回值上,在局部变量上,在成员函数上,const 是一个强有力的盟友。只要可能就用它,你会为你所做的感到高兴。

  Things to Remember

  ·将某些东西声明为 const 有助于编译器发现使用错误。const 能被用于对象的任何范围,用于函数参数和返回类型,用于整个成员函数。

  ·编译器坚持二进制位常量性,但是你应该用概念上的常量性(conceptual constness)来编程。(此处原文有误,conceptual constness 为作者在本书第二版中对 logical constness 的称呼,正文中的称呼改了,此处却没有改。其实此处还是作者新加的部分,却使用了旧的术语,怪!——译者)

  ·当 const 和 non-const 成员函数具有本质上相同的实现的时候,使用 non-const 版本调用 const 版本可以避免重复代码。

YOLOv8【第七章:损失函数篇·第1节】一文搞定,IoU系列损失函数! 🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏。该专栏系统复现并梳理全网各类 YOLOv8 改进与实战案例(当前已覆盖分类 / 检测 / 分割 / 追踪 / 关键点 / OBB 检测等方向),坚持持续更新 + 深度解析,质量分长期稳定在 97 分以上,可视为当前市面上 覆盖较全、更新较快、实战导向极强 的 YOLO 改进系列内容之一。 阅读详情

相关推荐

codemirror6 制作markdown编辑器(源码模式)

总体上感觉能用,但是不怎么友好,官方文档有点散乱,而且关键字高亮功能是独立出去的,去官方文档找半天,也没找到怎么改。EditorView.theme可以往EditorView模块中修改CSS的样式,从而影响编辑器的样式展示。"### 测试\n\n```javascript\nlet x = 'y'\n```"这个插件中的markdown语法的高亮样式。//这里指定markdown中代码块使用的解析扩展。开头的class样式,并且还需要在选择器前面添加。//markdown语言解析扩展。

qq_43203949的博客 1783

(数据结构)数组的物理大小和逻辑大小之间的区别?

物理大小,是它的数组单元的总数。 逻辑大小,是它当前可供应用程序使用的项的数目。 具有不同逻辑大小的数组图片。  

CaoMei_HuaCha的博客 2633

AI Agent Harness Engineering 创业PMF验证工具:用户满意度+留存率+业务指标监测表

在AI Agent创业的浪潮中,我们看到了无数产品如雨后春笋般涌现,但最终能够真正找到PMF并存活下来的却寥寥无几。根据CB Insights的数据,创业公司失败的首要原因(占42%)是"没有市场需求"——换句话说,就是没有找到PMF。AI Agent产品由于其特殊性(交互范式的变革、技术复杂度高、用户期望管理困难等),PMF验证变得更加具有挑战性。传统的SaaS产品PMF验证框架虽然有参考价值,但无法完全适用于AI Agent这种新型产品形态。

AI智能探索者的博客 331

【C++】 non-const函数调用const函数避免代码重复

const成员函数承诺绝不改变其对象的逻辑状态,non-const成员函数并没有这样的要求,所以为实现避免重复代码,non-const函数调用const函数的可行的,相反则是危险的。

Zebul的博客 894

详解Numpy中的transpose方法

最近在学Numpy碰到了关于数组转置和换轴的概念,尤其是对tanspose方法有些疑惑,尤其是多维,查了不少资料,终于搞懂了。 Numpy数组的轴(axis) 所谓的**轴(axis)**可以理解为数组的维度。 具体而言,二维数组就是有两个维度,如果从空间上看,它就是一个平面,由x轴和y轴构成,而与此相对应的,该二维数组就有两个轴,x轴对应0轴,y轴对应1轴。 同理,三维数组有三个维度,空间上...

BlankGrid的博客 936

PLC作为Modbus TCP客户端

PLC作为Modbus TCP客户端,Modbus Slave作为服务器

soledad_chao的博客 4378

位常量性(bitwise constness)与逻辑常量性(logical constness)

总结: "Bitwise constness" 强调在 const 成员函数中不能修改任何成员变量的值,而 "logical constness" 强调在 const 成员函数中不能修改外部可见的逻辑状态,但可以修改成员变量的值。2. Logical Constness(逻辑常量性): Logical constness 表示在 const 成员函数中不会修改外部可见的逻辑状态,但可能会修改成员变量的值,只要这些修改对外部不可见。是一个 const 成员函数,它计算矩形的面积。

f593256的博客 642

ChatIE:基于ChatGPT的零样本信息抽取实战指南

信息抽取是自然语言处理中的核心任务,旨在从非结构化文本中自动识别并结构化关键信息,如实体、关系及事件。传统方法依赖大量标注数据训练专用模型,流程复杂且成本高昂。随着大语言模型的发展,通过提示工程引导模型理解任务,实现了无需训练数据的零样本抽取能力,极大降低了技术门槛与应用成本。这种范式将信息抽取重构为多轮对话问题,通过分阶段提问引导模型逐步输出结构化结果,在快速原型验证、领域适配及小规模数据探索中展现出显著技术价值。本文以ChatIE项目为例,深入解析如何利用ChatGPT API,通过精心设计的提示词与两

weixin_30540691的博客 404

C++与STL笔记

纪录一下我学习Effective c++,Effective STL和More Effective c++的笔记

ylxc_tu的博客 1445

Frida实战:高效dump Android内存中的so文件与修复技巧

本文详细介绍了使用Frida工具dump Android内存中已解密so文件的实战技巧。针对加固应用静态分析失效的痛点,文章提供了从环境搭建、使用frida_dump脚本自动化抓取内存数据,到利用SoFixer工具修复ELF文件结构的完整流程,帮助逆向分析人员高效获取可分析的so文件。

tt34567的博客 527

从玩具到工业:手把手教你用Webots仿真Scara抓取(逆解实战篇)

本文详细介绍了如何在Webots仿真环境中实现Scara机械臂的逆解计算与抓取操作,涵盖从环境配置、逆运动学算法到轨迹规划与实时控制的完整流程。通过实战案例演示,帮助读者掌握机械臂逆解的核心技术,并应用于工业自动化场景,提升Scara机械臂的编程与控制能力。

weixin_30932215的博客 504

bitwise constness与logical constness【EC++笔记】

当成员函数为const时 constness(常量性) bitwise constness:不更换对象内任何一个字节,编译器判断成员变量没有赋值动作即可。 不足: class test { public: char& operator[](size_t index) const { return mPointer[index]; } test

CrazysPopcorn_qian的专栏 1895

AutoSAR RTE调度机制揭秘:从定时器事件到Runnable执行的完整流程

本文深入解析了AutoSAR RTE(运行时环境)的核心调度机制,详细阐述了从定时器事件触发到Runnable(可运行实体)执行的完整流程。通过剖析Rte_Start()函数、OS任务与警报的交互,以及事件驱动循环,揭示了RTE如何作为幕后指挥家,高效、可靠地协调软件组件间的周期性任务执行,是打通AutoSAR应用开发的关键。

weixin_29169899的博客 226

Effective C++解析 Item3:尽量使用const (补充)物理的与逻辑的常量性

上接: Effective C++解析 Item3:尽量使用const (续)const 修饰成员函数const修饰成员函数的具体含义: 有两种认同观点: 1. 物理常量性:当且仅当函数不修改任何成员数据时,可以使用const修饰成员函数。 2. 逻辑常量性:常成员函数仅可以在使用者未察觉的情况下修改成员数据。物理常量性的观点是不能说得通的,非const版的成员函数中修改了成员数据,且这些数

DoronLee的博客 518

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++程序员应了解的那些事(72)const使用小结 之 const保证物理常量性 ~ mutable拓展逻辑常量性

目录 【const的语义】//物理常量性与逻辑常量性 【const修饰变量】 【const修饰指针与引用】 【类中的const成员变量】 【const修饰函数】 【constexpr】 【const的语义】//物理常量性与逻辑常量性 C++中的const的目的是通过编译器来保证对象的常量性,强制编译器将所有可能违背const对象的常量性的操作都视为error。 对象的常量性可以分为两种:物理常量性(即每个bit都不可改变)和逻辑常量性(即对象的表现保持...

qfturauyls的博客 729

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C++总结:C++中的const和constexpr

C++中的const可用于修饰变量、函数,且在不同的地方有着不同的含义,现总结如下。 const的语义 C++中的const的目的是通过编译器来保证对象的常量性,强制编译器将所有可能违背const对象的常量性的操作都视为error。 对象的常量性可以分为两种:物理常量性(即每个bit都不可改变)和逻辑常量性(即对象的表现保持不变)。C++中采用的是物理常量性,例如下面的例子: 1 2 3 4 5 6 7 str

Sudouble的专栏 810

C++委員會不想讓你知道的事:const的真相

C++中const关键字的真相并非绝对不变性,而是语义标记。文章揭示了const的多个"漏洞":mutable允许const方法修改成员变量,指针和const_cast可绕过限制,存在未定义行为灰色地带。同时区分了物理const(内存不变)和逻辑const(外部状态不变)。在多线程环境中,const可能引发安全问题。C++委员会保留这些特性是为了兼容性、实用性和灵活性。建议将const视为接口契约而非安全保证,谨慎使用mutable和const_cast,优先考虑constexpr。co

王同学的博客 504

转,C++总结:C++中的const和constexpr

转自:https://www.cnblogs.com/fuzhe1989/p/3554345.html C++中的const可用于修饰变量、函数,且在不同的地方有着不同的含义,现总结如下。 const的语义 C++中的const的目的是通过编译器来保证对象的常量性,强制编译器将所有可能违背const对象的常量性的操作都视为error。 对象的常量性可以分为两种:物理常量性(即每个bit都不...

qingsong1001的专栏 217

const 常量

将"char &"类型的引用绑定到"const char"类型的初始值设定项时,限定符被丢弃。,因为你用cosnt修饰成员函数,如果你返回类型去掉const,就无法保证,使用者不会修改;

weixin_50860853的博客 467

还在纠结C++ mutable?一文带你理解 const 背后的“变”与“不变”

摘要: C++中的const关键字确保代码健壮性和安全性,但存在物理常量性与逻辑常量性的区别。mutable关键字允许在const函数中修改特定成员变量,以支持逻辑常量性,如缓存优化和线程同步。通过mutable,可以在保持对象对外行为不变的前提下优化内部实现,避免破坏const语义。典型应用场景包括懒加载缓存(提升性能)和互斥锁管理(确保线程安全),从而在不牺牲const正确性的情况下实现更灵活的代码设计。

Lion_Long的博客 1140

C++ const与mutable深度解析:从语法到线程安全缓存设计

在C++编程中,常量性(constness)是构建健壮、可维护代码的核心概念之一。const关键字通过强制不变性,为编译器优化和代码意图表达提供了基础保障,而mutable则作为其补充机制,允许在保持逻辑常量性的前提下修改特定成员。从技术原理看,const成员函数承诺不修改对象状态,这直接关系到接口契约的清晰度和线程安全的设计基础。在工程实践中,这对关键字协同工作,能够实现高效的惰性求值缓存、线程安全的访问控制等高级模式。特别是在多线程环境下,正确使用mutable配合互斥锁或原子变量,可以设计出既保持常量

weixin_30882895的博客 377

C++强制类型转换

December 7, 2015 9:45 AM在实现某个功能时,有时候我们会遇到类型转换的问题,在C++中,有些转换时自动执行的,无须程序员的介入,这一类被称作隐式转换,比如常见的算术类型之间的转换,以及有些内置函数会自动转换参数的精度(printf会自动将float转为double)。还有一类是显示转换,C++显示转换分类四类,需要说明的是,强制类型转换在很多情况下是有用的,但是它干扰了正常的类

HeiSeDiWei的博客 663

CPP学习笔记

一般情况下,class的专属常量只需要声明式,就像:只要不取地址是不需要定义式的。如果需要写定义式,应该写成因为在声明时已经复制,因此定义时不需要赋值。如果某些旧式编译器不支持在声明式赋初值,就在定义式中赋初值。在此时如果在类中需要定义一个数组的成员数量为该常量时,常量没有被赋值,可以使用the-enum-hack,即使用一个枚举类型的数值权当常量int使用。对于单纯常量,最好以 const 对象或 enum 替换#define。

weixin_46405072的博客 102

C++ const、volatile、mutable关键字深度解析:从语法到实战避坑指南

在C++编程中,理解内存模型和编译器行为是编写高效、健壮代码的基础。const关键字通过施加不变性约束,不仅保障了数据的正确性,还为编译器优化提供了可能,常用于定义常量、保护函数参数和实现常量成员函数。volatile则用于阻止编译器对特定变量的优化,确保每次访问都直接读写内存,这在内存映射I/O、信号处理等底层硬件交互场景中至关重要。mutable在保持对象逻辑常量性的前提下,允许修改某些内部状态,常用于实现内部缓存和线程安全同步。本文将结合多线程编程和内存模型,深入探讨这三个关键字的核心原理、典型应用场

weixin_30847939的博客 378

C++复习课程 001 基本内置类型 , 来自C++ Primer

基本内置类型可以分成算术类型和空类型(来自繁琐的C++Primer,巴拉巴拉...废话一大堆) ????????????????????????上面的都是废话 ,上图, 这个是C++Primer里面的解析???????????????? (有基础的同学其实是可以不用看图片的啦) 其中有标记的是不太经常使用的,像w_char 这种宽类型和char_16t ,char_32t 这种扩展的类型我们平时都是不怎么会使用的得到,要的时候可以 自己查。 (各种数据类型存放的数据我就不缀诉了) 但

qq_50510142的博客 280

C++关键字mutable(转滴)

<br /><br />关键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。<br />对象的状态<br />     一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。<br />    然而在一些情况下,对象的逻辑状态与其物理状态之间可能有差别。例如,

qinyushuang的专栏 458

C++中的恒定性

在这些容器中,存储的对象既是键(用于关联容器中的比较或无序容器中的哈希函数计算),也是值(包含一些数据,可能与键不同)。在这种情况下,我们讨论的是物理常量和逻辑常量被违反的情况,这样的成员函数可以声明为非常量。遗憾的是,我们经常会遇到一个术语上的误区:指向常量的引用被称为常量引用。互斥锁操作(锁定和解锁)是非 const 的,因此,如果互斥锁是类成员,那么使用它的成员函数在形式上不能是 const 的。因此,我们可以在任何需要指向常量类型的引用和指针的地方使用指向非常量类型的引用和指针。

2501_93209230的博客 668
下一篇: Code Exception Safe Functions
CyberLogix
博客等级 码龄24年 397粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值