C++语言特性相关
1.左值引用右值引用
左值(Lvalue,Locator Value)指的是可以被取地址的值,即在表达式结束后仍然存在的对象。例如,变量、数组元素、对象等都是左值。
左值引用用于绑定左值,并且通常用于传递和修改可变对象。
1 | int a = 10; |
右值(Rvalue,Right-hand value)指的是无法取地址的临时值,通常是表达式计算的结果,如字面量、临时变量等。
右值引用使用 &&
语法,用于绑定右值,使得右值可以被高效地移动,而不是复制。
1 | int&& rref = 10; // 10 是右值,可以绑定到右值引用 |
左值引用 vs 右值引用
左值引用 & |
右值引用 && |
|
---|---|---|
绑定对象 | 只能绑定左值 | 只能绑定右值 |
修改对象 | 可以修改 | 可以修改 |
适用场景 | 传递可变对象 | 移动语义、避免拷贝 |
常见用法 | 普通变量引用、函数参数 | 移动构造、移动赋值 |
2.左值引用和右值引用的转化
std::move()
:是一个转换工具,用于将左值强制转换为右值,从而触发移动语义std::forward<T>()
:主要用于泛型编程,保证在模板参数传递时,保留左右值的原始属性,实现完美转发。std::move_if_noexcept()
:在某些情况下,如果移动构造可能抛出异常,我们可能更希望使用拷贝构造。std::move_if_noexcept
可用于这种情况
3.指针的大小与用法
- 指针的大小和编译器的目标平台的位数,而与所指向的数据类型无关。如果是32位的机器,则指针的大小则是4Byte,如果是64位机器,那么指针的大小是8Byte。
- 指针存储变量的内存地址,使用
&
获取地址,使用*
解引用指针以访问数据。 - 指针作为函数参数:实现传址调用,允许函数直接修改原始数据。函数指针:用于回调机制或策略模式等
4.指针和引用的区别
总结对比表
特性 | 指针 | 引用 |
---|---|---|
是否需要初始化 | 不需要,可以为空 | 必须初始化 |
是否能重新指向 | 可以 | 不可以 |
是否可为空 | 可以指向 nullptr |
不可以 |
是否有独立内存 | 是,占用内存存储地址 | 否,与原变量共用内存 |
是否可修改值 | 通过 * 解引用后可修改 |
可修改(除非 const 修饰) |
典型应用场景 | 动态内存分配、数据结构 | 参数传递、引用更安全的别名 |
5.指针常量和常量指针
常量指针(const T*
):指向的值不能修改,但指针本身的指向可以更改。(即只能读,不能修改)
指针常量(T* const
):指针本身的指向不能更改,但指向的值可以修改。
6.函数指针的定义
函数指针 (Function Pointer) 是指向函数的地址的指针。与普通指针不同,函数指针指向的是可执行代码段中的函数入口地址,而非数据
函数指针的基本语法
定义函数指针的一般形式为:
1 | 返回类型 (*指针变量名)(参数类型列表); |
7.CPP中函数传递参数的方法
在 C++ 中,函数传递参数的方式主要有以下几种:
值传递(Pass by Value)
- 形参是实参的副本,在函数内对参数的修改不会影响原始数据。
- 适用于基本数据类型,但对于大对象会导致不必要的拷贝开销。
1
void func(int x) { x = 10; }
引用传递(Pass by Reference)
- 形参是实参的引用,函数内的修改会直接影响原始数据。
- 适用于需要修改参数的情况,或者避免拷贝大对象以提升效率。
1
void func(int& x) { x = 10; }
指针传递(Pass by Pointer)
- 形参是指向实参的指针,可以在函数内修改原数据。
- 需要检查指针是否为空,避免空指针访问错误。
1
void func(int* x) { if (x) *x = 10; }
常量引用传递(Pass by Const Reference)
- 适用于大对象的只读传递,既避免了拷贝,又保证了数据不会被修改。
1
void func(const std::string& str) { std::cout << str; }
右值引用传递(Pass by Rvalue Reference)(C++11及以上)
- 允许传递右值(临时对象),通常用于移动语义(move semantics),提高效率。
1
void func(std::string&& str) { std::cout << str; }
智能指针传递(Pass by Smart Pointer)(C++11及以上)
- 通过
std::shared_ptr
或std::unique_ptr
传递对象,管理内存生命周期。
1
void func(std::shared_ptr<int> ptr) { std::cout << *ptr; }
- 通过
不同的方式适用于不同的场景,应根据性能需求和数据安全性来选择合适的参数传递方式。
8.迭代器
迭代器(Iterator
)是 C++ STL(标准模板库) 中用于遍历容器(如 vector
、list
、map
等)的一种通用接口。迭代器提供了一种类似指针的方式来访问容器中的元素,同时又能适应不同类型的容器。
C++ 提供了 五种迭代器,分别适用于不同类型的容器和操作:
迭代器类型 | 说明 | 适用容器 |
---|---|---|
输入迭代器 (InputIterator ) |
只能 从前向后读取 数据 | istream_iterator |
输出迭代器 (OutputIterator ) |
只能 向前写入 数据 | ostream_iterator |
前向迭代器 (ForwardIterator ) |
可读可写,可单向移动 | forward_list |
双向迭代器 (BidirectionalIterator ) |
可读可写,可双向移动 | list 、map 、set |
随机访问迭代器 (RandomAccessIterator ) |
可读可写,可随机跳转 | vector 、deque |
常见 STL 容器的迭代器
容器 | begin() |
end() |
迭代器类型 |
---|---|---|---|
vector |
vector<int>::iterator |
vector<int>::iterator |
随机访问 |
list |
list<int>::iterator |
list<int>::iterator |
双向 |
map |
map<int, int>::iterator |
map<int, int>::iterator |
双向 |
set |
set<int>::iterator |
set<int>::iterator |
双向 |
9.野指针和悬空指针
野指针 vs 悬空指针
类别 | 定义 | 产生原因 | 如何修正 |
---|---|---|---|
野指针 | 未初始化的指针,指向未知地址 | 1. 没有初始化 2. 释放后未置空 3. 超出作用域 | 初始化指针为 nullptr |
悬空指针 | 指向已释放的无效内存 | 1. 释放后仍然访问 2. 作用域结束后访问 3. 二次释放 | 释放后将指针置空 |
10.类型转化
static_cast
vs dynamic_cast
特性 | static_cast |
dynamic_cast |
---|---|---|
转换时间 | 编译时 | 运行时 |
是否安全检查 | ❌ 无检查 | ✅ 运行时检查 |
适用范围 | 基本类型、多态类型、void* | 仅适用于多态类型 |
转换失败时 | 未定义行为 | 返回 nullptr (指针)/ 抛异常(引用) |
速度 | ⚡ 高效 | 🐢 慢(因运行时检查) |
四种转换方式对比
转换类型 | 转换方式 | 运行时检查 | 适用范围 | 推荐使用情况 |
---|---|---|---|---|
static_cast |
编译时转换 | ❌ 无 | 兼容类型转换 | ✅ 用于安全转换,如 int → double |
dynamic_cast |
运行时转换 | ✅ 有 | 多态类型(有虚函数) | ✅ 适用于父子类转换,确保安全 |
const_cast |
移除/添加 const |
❌ 无 | 指针/引用 | ✅ 需要修改 const 变量时 |
reinterpret_cast |
低级转换 | ❌ 无 | 指针/整数/位级转换 | ⚠️ 极少使用,仅用于底层编程 |