C++部分
-
野指针
- 没有初始化的指针为野指针,导致使用时崩溃
- 扩展:悬垂指针,通过
delete回收资源后,没有赋值为空,再次使用,由于指向的内存被回收了,导致崩溃
扩充:
- 解决方法:
- 在指针被
delete后,将指针赋值为nullptr,防止悬垂指针。 - 使用智能指针(
std::unique_ptr、std::shared_ptr),自动管理内存,减少手动错误。
- 在指针被
-
析构函数
- C++ 析构函数主要是为了在对象被销毁时回收构造时申请的资源
- 扩展:可以基于
RAII思想,管理对象资源的生命周期
扩充:
- 析构函数的特性:
- 如果类中包含指针成员,析构函数必须显式释放内存,否则会导致内存泄漏。
- 基类的析构函数应声明为
virtual,确保派生类析构时正确调用基类析构函数。
-
内存布局
.data: 初始化的全局变量.rodata: 存储常量.bss: 未初始化的全局变量,默认初始化为0.text: 存储函数
扩充:
- 堆与栈:
- 栈:用于函数调用、局部变量存储,自动分配和释放,快速且安全。
- 堆:动态内存分配,生命周期由程序员控制,容易产生内存泄漏。
-
内存分配
malloc,new在堆上申请空间
扩充:
- 区别:
malloc返回void*,不调用构造函数,使用时需要显式类型转换。new返回对象类型指针,自动调用构造函数并初始化内存。
- 释放内存:
malloc配合free,new配合delete,不能混用,否则会引发未定义行为。
-
多线程要注意什么
- 数据竞争
- 锁的使用
扩充:
- 常见问题:
- 死锁:多个线程循环等待资源,导致无法继续执行。
- 线程安全:使用互斥锁(
std::mutex)、条件变量等同步机制防止资源争用。
- 优化:
- 使用
std::lock_guard或std::unique_lock管理锁,防止忘记释放锁。
- 使用
-
单例模式
- 为什么使用单例
扩充:
- 单例的作用:
- 确保类只有一个实例,且提供全局访问点。
- 常用于日志、配置管理、数据库连接等场景。
- 实现方式:
- 懒汉模式(延迟初始化)
- 饿汉模式(程序启动时初始化)
- 使用
std::call_once和std::mutex保证线程安全。
- 为什么使用单例
项目部分
-
即时通讯软件,1对1聊天的聊天记录如何保存,群组的呢
回答:- 1对1聊天记录:可以保存到本地数据库(如SQLite)或者云端服务器,按用户ID建立索引以便快速查询。
- 群组聊天记录:可以使用分布式数据库,按群ID和消息时间戳存储,便于同步和检索。
-
登录应该保存用户的哪些信息
回答:- 用户ID、用户名
- 用户凭据(如Token、加密后的密码)
- 登录状态和过期时间
- 设备信息(如设备ID)
-
聊天界面有多种气泡,如文本,语音,图片。在接收到消息时,本地客户端如何判断是哪种类型的气泡
回答:- 消息格式应采用统一的消息协议,包含消息类型字段(如文本、语音、图片)。
- 通过协议解析消息,判断消息类型,并调用对应的UI组件进行渲染。
-
如何实现消息的撤回
回答:- 在服务端和客户端记录消息的唯一ID。
- 用户发起撤回请求,服务端验证权限后标记该消息为“撤回状态”。
- 客户端接收到撤回指令后更新消息显示状态,如提示“消息已撤回”。
-
离线消息如何持久化
回答:- 服务端将离线消息存储到数据库或缓存中,按用户ID进行索引。
- 当用户上线时,查询对应的离线消息并推送到客户端。
- 客户端收到离线消息后,存储到本地持久化数据库(如SQLite)。