赞
踩
智能指针的作⽤是管理⼀个指针,避免程序员申请的空间,在函数结束时忘记释放,造成内存泄漏这种情况发⽣。因为智能指针就是⼀个类,当超出了类的作⽤域是,类会⾃动调⽤析构函数,析构函数会⾃动释放资源。
1. auto_ptr(C++98 的⽅案,C11 已抛弃)
auto_ptr<std::string> p1 (new string ("hello"));
auto_ptr<std::string> p2;
p2 = p1; //auto_ptr 不会报错.
此时不会报错,p2 剥夺了 p1 的所有权,但是当程序运⾏时访问 p1 将会报错。所以存在潜在的内存崩溃问题!
2. unique_ptr(替换 auto_ptr )
实现独占式拥有概念,保证同⼀时间内只有⼀个智能指针可以指向该对象。它对于避免资源泄露特别有⽤。
unique_ptr<string> p3 (new string (auto));
unique_ptr<string> p4;
p4 = p3;//此时会报错
编译器认为 p4=p3 ⾮法,避免了 p3 不再指向有效数据的问题。
3. shared_ptr(共享型,强引⽤)
实现共享式拥有概念,多个智能指针可以指向相同对象,该对象和其相关资源会在“最后⼀个引⽤被销毁”时候释放。当我们调⽤ release() 时,当前指针会释放资源所有权,计数减⼀。当计数等于 0
时,资源会被释放。
4. weak_ptr(弱引⽤)
weak_ptr 是⼀种不控制对象⽣命周期的智能指针,它指向⼀个 shared_ptr 管理的对象。C++11标准虽然将 weak_ptr 定位为智能指针的一种,但该类型指针通常不单独使用。
当 weak_ptr 类型指针的指向和某一 shared_ptr 指针相同时,weak_ptr 指针并不会使所指堆内存的引用计数加 1;同样,当 weak_ptr 指针被释放时,之前所指堆内存的引用计数也不会因此而减 1。
weak_ptr 是⽤来解决 shared_ptr 相互引⽤时的死锁问题,如果说两个 shared_ptr 相互引⽤,那么这两个指针的引⽤计数永远不可能下降为0,也就是资源永远不会释放。解决办法:把其中⼀个改为weak_ptr就可以。
栈:由编译器管理分配和回收,存放局部变量和函数参数。
堆:需要⼿动 new malloc delete free 进⾏分配和回收,但可能会出现内存泄漏和空闲碎⽚的情况。
全局/静态存储区:存储初始化和未初始化的全局变量和静态变量。
常量存储区:存储常量,⼀般不允许修改。
代码区:存放程序的⼆进制代码。
int *p; // 合法
int &r; // 不合法
int a = 996;
int &r = a; // 合法
int a = 996;
int *p = &a; // 初始化, p 是 a 的地址
int &r = a; // 初始化, r 是 a 的引用
int b = 885;
p = &b; // 合法, p 更改为 b 的地址
r = b; // 不合法, r 不可以再变
int a = 996;
int *p = &a;
int &r = a;
cout << sizeof(p); // 返回 int* 类型的大小
cout << sizeof(r); // 返回 int 类型的大小
9.作为函数参数时,传指针的实质是传值,传递的值是指针的地址
比如void test1(int* p) ,给*p赋值会导致实参也改变,但给p赋值,实参不会改变
传引⽤的实质是传地址,传递的是变量的地址,被调函数对形参的任何操作都会影响主调函数中的实参
#include <iostream> using namespace std; void test1(int* p, int& q) { *p = 200; q = 200; } void test2(int* p) { int a = 300; p = &a; } void main() { int num1 = 100; int num2 = 100; test1(&num1, num2); cout << num1 << endl; cout << num2 << endl << endl; test2(&num1); cout << num1 << endl; } // 输出结果为 200 200 200
static关键字详解
static 作⽤:控制变量的存储⽅式和可⻅性
const 关键字
用 const 定义的变量的值是不允许改变的,即不允许给它重新赋值,即使是赋相同的值也不可以。
const修饰指针和引用
如果 const 位于⼩星星的左侧,则 const 就是⽤来修饰指针所指向的变量;
int const *pi = &a;
如果 const 位于⼩星星的右侧,则 const 就是修饰指针本身。
int* const pi = &i;
1.重载 :⼏个具有不同参数列表的同名函数,重载不关⼼函数的返回类型
2.重写:派⽣类中重新定义⽗类中除了函数体外完全相同的虚函数,返回值和形参都不能改变
3.重定义:派⽣类重新定义⽗类中相同名字的⾮虚函数,参数列表和返回类型都可以不同
class test{
int x;
int y;
test(test &another){
x = another.x;
y = anoyher.y;
}
}
// 调用拷贝构造函数
test test2(test1);
test test2 = test1;
test(int a) {
x = a;
y = 0;
}
// 调用变换构造函数
test test1 = 100;
test test2;
test2 = 100;
通过在子类中指定继承的函数来自哪个父类:son.Parent_f::show();
(1)在定义函数时添加inline关键字,在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。(只在函数声明时添加inline关键字则无效)
(2)函数调用是有时间和空间开销的,如果函数体代码比较多,需要较长的执行时间,那么函数调用机制占用的时间可以忽略;如果函数只有一两条语句,那么大部分的时间都会花费在函数调用机制上
(3)如果内联函数的函数体非常大,那么编译后的程序体积也将会变得很大,一般只将那些短小的、频繁调用的函数声明为内联函数。
(4)对函数作 inline 声明不是强制性的,并非一经指定为 inline 编译器就必须这样做。编译器有自己的判断能力,它会根据具体情况决定是否这样做。
(5)内联函数不允许使用循环语句和开关语句(switch)
1、auto : 根据变量的初始值推导出变量类型。
C++11中新增,在定义auto变量的时候就必须初始化
知道类型没有问题但⼜不想完整地写出类型的时候使用,最常用的地方如STL标准库中的迭代器:
2、decltype:根据表达式exp推导出变量name的类型,与初始化值value无关
decltype(exp) name = value;
decltype(exp) name
decltype(a) b = 1; //b 被推导成了 int
(1)如果 exp 是一个不被()包围的表达式,或一个单独的变量,那么 decltype(exp) 的类型就和 exp 一致
(2)如果 exp 是函数调用,那么 decltype(exp) 的类型就和函数返回值的类型一致。
(3)如果 exp 是一个左值,或者被括号( )包围,那么 decltype(exp) 的类型就是 exp 的引用
int n = 0, m = 0;
decltype(n + m) c = 0; //n+m 得到一个右值,符合推导规则一,所以推导结果为 int
decltype(n = n + m) d = c; //n=n+m 得到一个左值,符号推导规则三,所以推导结果为 int&
(1)volatile代表变量的易变性,变量的值可能随时被修改;
(2)volatile告诉编译器,不要对访问该变量的代码进行各种各样的优化;
(3)volatile修饰的变量每次必须从内存中读取值,不能从寄存器中读取。
(1)malloc与free是C/C++的标准库函数,new/delete是C++的运算符
(2)对象在创建的同时要自动执行构造函数,对象的消亡之前要自动执行析构函数
(3)malloc/free是库函数而不是运算符,不在编译器控制权限之内
(4)使用malloc/free并不会自动调用构造/析构函数
C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存
内部数据类型没有构造与析构,对它们而言malloc/free和new/delete是等价的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。