堆和栈的区别
堆用来存放动态分配的对象(new出来的);
栈用来存在函数内定义的非static对象,如局部变量等,只有在它的程序运行的时候才存在;
静态内存用来保存static对象;
static在使用前分配,程序结束时销毁。栈和静态内存由编译器自动创景和销毁,堆由程序控制。
程序编译过程
.c->.i->.s->.o->exe
预处理器->编译器->汇编器->连接器
内存泄漏
用动态存储分配函数动态开辟的空间,在使用完后未释放。
智能指针
为了更安全的使用动态内存,智能指针与常规指针相似,但是能够自动释放所指向的对象
(不要混用普通指针和智能指针)
shared_ptr, unique_ptr, weak_ptr, 都在头文件memory中
shared_ptr允许多个指针指向同一个对象
unique_ptr独占所指向的对象
weak_ptr是一种弱引用,指向shared_ptr所管理的对象
shared_ptr<string> p1; //指向string
shared_ptr<list<int>> p2; //指向int的list
使用make_shared函数分配
//指向一个值为42的int的shared_ptr
shared_ptr<int> P3 = make_shared<int>(42);
//指向一个值为“9999999999”的string
shared_ptr<string> P4 = make_shared<string>(10,'9');
//指向一个值初始化的int,即值为0
shared_ptr<int> p5 = make_shared<int>();
常用auto定义,较为简单
//指向一个动态分配的空vector<string>
auto p6 = make_shared<vector<string>>();
auto p7(p6);//p7和p6指向同一个对象,该对象有两个引用者
由于unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作
unique_ptr<double> p1; //指向一个double的unnique_ptr
unique_ptr<int> p2(new int(42)); //指向一个值为42的int
虽然不能拷贝或赋值unique_ptr,但是可以通过调用release或reset将指针的所有权从一个unique_ptr转移给另一个unique_ptr(非const的)
//将所有权从p1转移给p2
unique_ptr<string> p2(p1.release()); //releaase是将p1置空
//将所有权从p3转移给p2
p2.reset(p3.release()); //reset释放了p2原来指向的内存
release成员返回unique_ptr当前保存的指针并将其置空;
reset成员接收一个 可选的指针参数,令unique_ptr重新指向给定的指针。
调用release会切断unique_ptr和它原来管理的对象之间的联系。
const用途
1、定义只读变量或常量
2、修饰函数的参数和函数的返回值
3、修饰函数的定义体,被const修饰的成员函数代表不能修改成员变量的值,可以调用,不能修改
static用途
1、静态变量
2、静态函数
3、类的静态成员数据
4、类的静态成员函数
malloc/free和new/delete
都可以用于申请动态内存和释放内存
new/delete但是运行符,可以执行构造函数和析构函数,而malloc/free是库函数,不能执行构造函数和析构函数。(所以面向对象只能用new/delete)
new在申请内存时就可以初始化,而malloc就不行。
类型转换
1、静态类型转换,即static_cast
double a = 1.23;
int b - static_cast<int> (a);
2、子类与父类间的多态类型转换,即dynamic_cast
用于将基类的指针或引用安全的转换成派生类的指针或引用
dynamic_cast<type*>(e);
dynamic_cast<type&>(e);
dynamic_cast<type&&>(e);
Derived *dp = dynamic_cast<Derived*>(bp);
type必须是一个类类型,e的类型是type的公有派生类,或e的类型是目标type的共有基类。
假定基类至少含有一个虚函数,Deriver是基类的公有派生类,有一个指向基类的指针bp,则可通过上述代码最后一行将基类指针转化成指向子类的指针。
3、去掉const属性的转换,即const_cast
const char *cp;
char *p = const_cast<char*>(pc);
4、重新解释类型转换,即reinterpret_cast
即堆数据的二进制重新解释,但是不改变其值,较为危险,不建议使用
int *ip;
char *pc = reinterpret_cast<char*>(ip);
静态成员变量和静态成员函数
静态成员变量:
1、需要在类内声明(加static),在类外初始化(不加static);
2、静态成员变量在类外单独分配存储空间内,位于全局数据区,因此静态成员变量的声明周期不依赖于类的某个对象,而是所有类的对象共享静态成员变量;
3、可以通过对象名直接访问公有静态成员变量
4、可以通过类名直接调用公有静态成员变量,即不需要通过对象
静态成员函数
1、静态成员函数是所有类所共享的
2、静态成员函数可以访问静态成员变量,但无法访问普通成员变量,需要通过对象访问,但普通成员函数既可以访问普通成员变量,也可以访问静态成员变量
3、可以通过对象名直接访问公有静态 成员函数;
4、可以通过类名直接 调用公有静态成员函数,不需要通过对象。
指针和引用
都是地址
指针是指向一块内存,它的内容是所指的内存的地址,而引用则是某块内存的别名
引用在内部实现是借助指针实现的,一些场合下可以代替指针,如形参
指针是实体,而引用是个别名
引用只能在定义的时候被初始化一次,后续不可改变,而指针是可以改变的
引用不能为空,指针可以为空
sizeof引用得到的是所指向的变量的大小,而sizeof指针得到的是指针本身的大小
指针和引用的++不一样
引用是类型安全的,而指针不是
引用也占用内存空间,因为引用内部也是通过指针实现的
三目运算符
(a>b ? a:b) = 1;
C++中三目运算符的返回结果是一个引用,因此可以作为左值,相当于对引用赋值
指针数组与数组指针
数组指针:指向数组的指针,本质为指针
指针数组:元素全为指针的数组