八股总结
四种智能指针
管理指针,避免忘记释放空间造成内存泄露
auto_ptr
p2剥夺p1的所有权,访问p1会造成内存崩溃
unique_ptr
同一时间内只有一个智能指针可以指向该对象,利于避免资源泄露。
若上例采用unique_ptr
,则编译器认为非法,避免了p3不再指向有效数据的问题。
shared_ptr
强引用
shared_ptr
实现共享式拥有概念,多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。
可以通过成员函数use_count()
来查看资源的所有者个数,除了可以通过 new 来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr 来构造。当我们调用 release() 时,当前指针会释放资源所有权,计数减一。当计数等于 0 时,资源会被释放。
引用计数是线程安全的,但被管理的对象不一定线程安全。
weak_ptr
可以将其中一个shared_ptr
转换成weak_ptr
。
C++中内存分配情况
栈 由编译器管理分配和回收,存放局部变量和函数参数。
堆 程序员管理 手动new malloc delete free
全局/静态存储区 初始化/未初始化区
常量存储区 字符串等
代码区
C++中指针参数传递和引用参数传递
引用参数传递。间接寻址操作到主调函数中的相关变量
符号表上,指针变量的地址就是指针本身的地址,因此指针可以改变其指向的对象,而引用的地址就是其引用的变量的地址,无法改变。
Static
修饰局部变量,放到静态存储区,生命周期与程序相同,作用域不变!
修饰全局变量、函数 用 static 对全局变量进行修饰改变了其作用域范围,由原来的整个工程可⻅变成 了本文件可⻅。修饰函数与修饰全局变量类似,改变了作用域。
函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问。 在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;
类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷⻉;
类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的 static 成员变量。
Const
int*
A pointer to an integer.
Yes
Yes
const int*
A pointer to a constant integer. You can change where the pointer points, but you can't change the value it points to.
No
Yes
int const*
Same as const int*
. A pointer to a constant integer.
No
Yes
int* const
A constant pointer to an integer. You can change the value it points to, but you can't change where the pointer points.
Yes
No
int&
A reference to an integer. You can change the value it refers to, but you can't make it refer to a different integer.
Yes
No (referenced object is fixed)
const int&
A reference to a constant integer. You can't change the value it refers to, nor can you make it refer to a different integer.
No
No (referenced object is fixed)
int const&
Same as const int&
. A reference to a constant integer.
No
No (referenced object is fixed)
int& const
This is actually incorrect syntax. References themselves can't be const or non-const. This will cause a compiler error.
N/A
N/A
We cannot pass the address of const int
to int *
.
We can pass the address of const int
to const int *
.
A const object cannot call non-const member functions.
The idea is that we should by no means change the const value.
局部常量放在栈上,全局变量编译期不分配内存,放在符号表中提高访问效率,字面值常量放在常量区。
重载,重写,重定义
重载 同⼀可访问区内被声明的⼏个具有不同参数列表的同名函数,依赖于 C++函数名字的修饰会将参数加在后⾯,可以是参数类型,个数,顺序的不同。根据参数列表决定调⽤哪个函数,载不关⼼函数的返回类型。
重写 派⽣类中新定义⽗类中除了函数体外完全相同的虚函数,注意被写的函数不能是 static 的,⼀定要是虚函数,且其他⼀定要完全相同。要注意,重写和被重写的函数是在不同的类当中的,重写函数的访问修饰符是可以不同的,尽管 virtual 中是 private 的,派⽣类中写可以改为 public。
重定义(隐藏) 派⽣类新定义⽗类中相同名字的⾮ virtual 函数,参数列表和返回类型都可以不同,即⽗类中除了定义成 virtual 且完全相同的同名函数才不会被派⽣类中的同名函数所隐藏(定义)。
强制类型转换
static_cast:
dynamic_cast:
const_cast:
reinterpret_cast:
野指针与悬空指针
野指针(wild pointer):就是没有被初始化过的指针。⽤ gcc -Wall 编译, 会出现 used uninitialized警告。
悬空指针:是指针最初指向的内存已经被释放了的⼀种指针。
函数指针
new/delete, malloc/free的区别
执⾏ new 实际上执⾏两个过程:1.分配未初始化的内存空间(malloc);2.使⽤对象的构造函数对空间进⾏初始化;返回空间的⾸地址。如果在第⼀步分配空间中出现问题,则抛出 std::bad_alloc 异常,或被某个设定的异常处理函数捕获处理;如果在第⼆步构造对象时出现异常,则⾃动调⽤ delete 释放内存。
执⾏ delete 实际上也有两个过程:1. 使⽤析构函数对对象进⾏析构;2.回收内存空间(free)。
Last updated