当前位置: 首页 > news >正文

C++ 中的 const 、 mutable与new

C++ 中的 constmutable

在 C++ 中,const 可以看作是一种“承诺”:承诺某些东西在程序执行过程中不会改变。它不仅可以修饰变量,还可以修饰指针、类成员函数、函数参数等,是一种广泛用于只读保护接口契约的机制。


1. 基本常量

const int MAX_AGE = 90;
  • MAX_AGE 是只读变量,不能被修改。

  • 对比普通变量,这是一个编译期约束。


2. 指针与 const

2.1 指向常量的指针

const int* a = new int;
a = &MAX_AGE; // 合法,指针本身可变
*a = 2;       // ❌ 不合法,不能修改指针指向的数据
  • const* 左边 → 指针指向的数据是常量,指针可变。

2.2 常量指针

int* const a = new int;
a = &MAX_AGE; // ❌ 不合法,指针本身不能改
*a = 2;       // 合法,可以修改指向的数据
  • const* 右边 → 指针本身是常量,指向的数据可变。

2.3 指向常量的常量指针

const int* const a = &MAX_AGE;
// a 和 *a 都不可修改

3. 类成员函数中的 const

在类成员函数后加 const,表示该方法不会修改对象的成员变量(除了 mutable 修饰的成员)。这样,常量对象或常量引用就可以调用该方法。

class Entity {
private:int m_X, m_Y;
public:int GetX() const {// m_X = 2; // ❌ 不合法return m_X;}
};
  • 尾部 const 使方法成为只读方法。

  • 如果对象是 const Entity e; 或通过 const Entity& e 访问,只能调用 const 成员函数。


3.1 可同时提供 const / 非 const 版本

为了兼容常量对象和非常量对象,可以提供两个版本的成员函数:

class Entity {
private:int m_X, m_Y;
public:int GetX() const {  // const 版本return m_X;}int GetX() {        // 非 const 版本return m_X;}
};
  • 对于 const Entity& e,默认调用 const 版本。

  • 对于普通对象 Entity e,调用非 const 版本。


4. mutable

  • mutable 修饰成员变量,即使在 const 方法中,也可以修改它。

  • 常用于缓存或记录状态。

class Entity {
private:int m_X, m_Y;mutable int var;
public:int GetX() const {var = 2; // 合法return m_X;}
};
  • 这样可以在 const 方法中修改 var,而不会破坏 const 约束。


5. const 指针与成员函数结合示例

void PrintEntity(const Entity* e) {e = nullptr;          // ✅ 合法,修改指针本身std::cout << e->GetX(); // ✅ 可以调用const成员函数
}

⚠️问题:

  • const Entity* e → 指针 e 可以指向其他地址,但不能修改它指向的对象内容(*e)。

  • 调用 GetX() 合法,因为 GetX()const

    void PrintEntity(const Entity& e) {// e = Entity(); // ❌ 不合法,不能修改对象内容std::cout << e.GetX() << std::endl; // ✅ 可以调用const成员函数
    }
    

  • const Entity& ee对常量对象的引用,不能修改对象。

  • 如果 GetX() 没有 const,调用就会报错:

    • 因为编译器认为可能修改对象。

  • 调用 const 成员函数是安全的

    e = Entity();
    

    本质上是:

  • 创建了一个临时的 Entity 对象。临时对象通常在表达式结束时就会被销毁。

  • 尝试把它 赋值给 e,也就是修改 e 指向的对象内容。

  • econst 引用,指向的对象不可修改。

  • 赋值操作会修改对象内容,所以编译器报错。


6. lambda 表达式中的 mutable

  • 默认捕获 [=] 是按值捕获,内部变量是 const 副本,不能修改。

  • 可以用 mutable 来允许修改副本。

int x = 8;
auto f = [=]() mutable {x++;std::cout << x << std::endl;
};
f(); // 输出 9,外部 x 不变
  • 捕获引用 [&] 时,直接修改外部变量。

int x = 8;
auto f = [&]() {x++;
};
f();
std::cout << x << std::endl; // 输出 9,外部 x 被修改

7. 总结

用法说明
const int xx 只读,不可修改
const int* p指向常量的指针,*p 不能改,p 可改
int* const p常量指针,p 不可改,*p 可改
const int* const p指向常量的常量指针,p 和 *p 都不可改
int GetX() constconst 成员函数,不修改对象
mutable int var即使在 const 方法中也可修改
const T&常量引用,安全高效传参
mutable + lambda允许修改按值捕获的副本

C++ 中的 new 操作符与动态内存管理

在 C++ 中写程序时,尤其是涉及类和对象的时候,内存管理和性能优化是必须关心的问题。new 是 C++ 提供的一个关键工具,用于在 堆(heap) 上分配内存。


1. new 的基本用法

new 的主要作用是在堆上分配内存并调用构造函数。例如:

int* a = new int;       // 分配单个 int,默认初始化
int* b = new int(5);    // 分配并初始化为 5
int* c = new int[10];   // 分配 10 个 int 的数组

对于类对象:

Entity* e1 = new Entity();      // 默认构造函数初始化
Entity* e2 = new Entity[10];    // 分配对象数组,每个对象调用构造函数

释放内存

动态分配的内存必须手动释放:

delete e1;       // 释放单个对象
delete[] e2;     // 释放对象数组

2. 默认初始化 vs 值初始化

在使用 new 时,初始化方式不同,行为也不同:

Entity* e = new Entity(); // 值初始化Entity* e = new Entity; // 默认初始化
  • 值初始化

    • 内置类型成员(intfloat、指针等)会被 零初始化

    • 类类型成员(如 std::string)会调用 默认构造函数

  • 默认初始化

    • 内置类型成员保持 随机垃圾值

    • 类类型成员同样调用默认构造函数。


3. new 的工作原理

new 本质上是一个操作符,可以理解为函数:

  1. 在堆上分配指定大小的内存。

  2. 返回一个 void* 指针(无类型的指针)。

  3. 调用对象的构造函数进行初始化。

  4. 返回指定类型的指针。

实际上,new 底层通常会调用 C 函数 malloc 来分配内存,然后再调用构造函数。
例如:

Entity* e = new Entity(); 
// 相当于
Entity* e = (Entity*)malloc(sizeof(Entity));
// 再调用构造函数初始化

为什么需要类型指针?

指针只是内存地址,之所以有类型,是为了知道如何从该地址读取多少字节以及如何操作这些字节。


4. 堆内存管理注意事项

  • new 分配的内存不会自动释放,必须调用 delete

  • 使用 new[] 分配数组时,必须用 delete[] 释放。

  • 动态内存管理不当会导致:

    • 内存泄漏(未释放)

    • 内存重用问题(未释放的内存仍被占用)


5. placement new(定位 new)

placement new 允许你在已分配的内存上直接构造对象,而不分配新的堆内存:

int* buffer = new int[200];        // 分配内存
Entity* e = new(buffer) Entity();  // 在 buffer 地址上构造对象
  • 这不会分配新内存,只调用构造函数。

  • 常用于 内存池自定义分配策略


6. 对比 malloc 与 new

特性mallocnew
分配内存仅分配分配内存并调用构造函数
返回类型void*指定类型指针
初始化不初始化可值初始化或默认初始化
释放方式freedelete / delete[]
C++ 推荐方式不推荐推荐,支持构造函数调用

7. 小结

  • new 是 C++ 的动态内存操作符,负责堆内存分配 + 构造函数调用。

  • 使用 deletedelete[] 来释放内存。

  • 优先使用 值初始化 保证内置类型成员为零,类成员正确构造。

  • 对性能敏感时,可以使用 placement new 或内存池优化。

http://www.dtcms.com/a/407363.html

相关文章:

  • MEMS加速度计如何让无人机在狂风中稳如磐石?
  • 云望无人机图传系统解析:开启高效航拍新时代
  • 临沂建设网站nginx wordpress优化
  • EUDR认证审核条件是什么?
  • 不止一页:页面路由与导航
  • Amazon Comprehend 自然语言处理案例:从概念到实战
  • 茶树修剪周期规划:春剪与秋剪对新梢萌发的影响
  • 美食网站开发目的与意义郑州投资网站建设
  • hive窗口函数与自定义函数
  • 建一个个人网站多少钱精准营销的好处
  • STL的list模拟实现(带移动构造和emplace版本)
  • 当技术不再是壁垒:UI设计师的情感化设计与共情能力成为护城河
  • 公司网站建设 目录dw用设计视图做网站
  • 4-4〔O҉S҉C҉P҉ ◈ 研记〕❘ WEB应用攻击▸本地文件包含漏洞-B
  • Acuvi 旗下PiezoMotor电机:Piezo LEGS 如何解锁纳米级运动控制?
  • 运营专员技能提升培训班推荐:从执行到数据驱动
  • 商城网站建设如何交谈电子产品展示网站模板
  • 银川网站seo邯郸注册公司
  • 网站开发的基本语言网站被拔毛的原因
  • 吉林市网站建设招标在线网站
  • 奈氏准则(奈奎斯特定理Nyquist‘s Theorem)和香农采样定理(Shannon Sampling Theorem)
  • 用sql网站建设基本流程小说网站开发实训报告
  • vps如何创建网站wordpress onthego
  • 东莞做网站哪家最好商城源码开源
  • uniapp生成二维码组件全能组件复制即用
  • 如何安装网站模版seo排名优化课程
  • Git 多人协作(2)
  • 网站建设模式有哪些方面网站精神文件建设专栏
  • 外贸建站服务器怎么选网站备案每年审吗
  • 【不背八股】17.什么是Bert?