Debug:调试版本,包含调试信息,所以容量比Release大,不对程序进行优化,会生成.exe和.dll文件,还有.pdb文件(记录中断调试信息)
Release:发布版本,编译时对应用程序进行优化,以便用户很好使用
从静态存储区分配:编译时分配,程序运行时都存在,全局变量,static变量、常量在这里存储
在栈区分配:代码执行时创建,执行结束自动释放。栈内存分配运算内置于处理器,效率高,容量有限
在堆区分配:动态分配内存。程序员自己new和delete,使用灵活,如果不回收,运行会出现内存泄漏,频繁分配和释放不同大小的堆空间会产生堆内碎块。
在C++中,内存分为五区:堆,栈,自由存储区、全局/静态存储区、常量存储区。
栈:编译器在需要时自动分配,不需要时自动清除,存放局部变量、函数参数
堆:new分配的内存快,由程序员自动释放(编译器不管),如果程序员不释放,资源将在操作系统结束后自动回收(Java自动回收机制)。
自由存储区:malloc分配的内存块,free来释放,和堆相似
全局/静态存储区:存放全局变量和静态变量
常量存储区:存放常量,不允许修改。
自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆。
堆 | 栈 | |
---|---|---|
管理方式 | 堆中资源由程序员控制 | 栈资源由编译器自动管理,无需手工控制 |
内存管理机制 | 系统有一个记录空闲内存地址的链表,当系统收到程序申请时,遍历该链表,寻找第一个空间大于申请空间的堆结点,删除空闲结点链表中的该结点,并将该结点空间分配给程序 | 只要栈的剩余空间大于所申请空间,系统为程序提供内存,否则报异常提示栈出 |
空间大小 | 堆是不连续的内存区域(系统是用链表来存储空闲内存地址,不是连续的),堆大小受限于计算机系统中有效的虚拟内存(32bit 系统理论上是4G),堆的空间比较灵活,比较大 | 栈是一块连续的内存区域,大小是操作系统预定好的 |
碎片 | 对于堆,频繁的new/delete会造成大量碎片,使程序效率降低 | 对于栈,它是一个先进后出的队列,进出一一对应,不会产生碎片。 |
生长方向 | 堆向上,向高地址方向增长。 | 栈向下,向低地址方向增长。 |
分配方式 | 堆都是动态分配 | 栈有静态分配和动态分配,静态分配由编译器完成(如局部变量分配) |
线程:是操作系统能够进行CPU调度的最小单位。
多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程。
基于进程的多任务处理是程序的并发执行。
基于线程的多任务处理是同一程序片断的并发执行。
多线程并发:即多个线程同时执行,把一个任务拆分多个任务,然后由不同线程处理不同子任务,使得多个子任务同时进行。
同步:在发出调用时,没得到结果前,该调用不返回;
异步:调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
类似于银行一个柜台和多个柜台。
小笔记:
需要包含头文件 #include
std::thread 默认构造函数,创建一个空的 std::thread 执行对象。
可以是 函数指针、函数对象、lambda表达式
【C++】Sleep函数的用法
功能:执行挂起一段时间,等待一段时间在继续运行
需要引用头文件:#include
#include
#include //声明管理线程的函数和类
//一个虚函数
void foo(int z)
{
for (int i = 0; i < z; i++)
{
std::cout << "线程使用函数指针作为可调用参数" << std::endl;
}
}
class thread_obj
{
public:
void operator()(int x)//重载()运算符
{
for (int i = 0; i < x; i++)
{
std::cout << "线程使用函数对象作为可调用参数" << std::endl;
}
}
};
int main()
{
std::cout << "线程1、2、3独立运行" << std::endl;
//函数指针
std::thread th1(foo,3);//创建一个名为th1的线程
//函数对象
std::thread th2(thread_obj(), 3);
//lambda表达式
auto f=[](int x)
{
for (int i = 0; i < x; i++)
{
std::cout << "线程使用lambda表达式作为可调用参数" << std::endl;
}
};
std::thread th3(f, 3);
th1.join();
th2.join();
th3.join();
system("pause");
return 0;
}
输出:
线程1、2、3独立运行
线程使用lambda表达式作为可调用参数
线程使用lambda表达式作为可调用参数
线程使用lambda表达式作为可调用参数
线程使用函数对象作为可调用参数
线程使用函数对象作为可调用参数
线程使用函数对象作为可调用参数
线程使用函数指针作为可调用参数
线程使用函数指针作为可调用参数
线程使用函数指针作为可调用参数
小笔记:
join()函数
th1调用了join函数,所以必须等到th1完成,th1.join()才能返回
需要包含头文件:#include
#include
//线程函数
int thread_fun(int x)
{
for (int i = x; i >=0; i-=2)
{
std::cout << "子线程:i=" << i << std::endl;
Sleep(100);
}
return 0;
}
int main()
{
std::thread th1(thread_fun, 10);//创建线程
//主线程
for (int i = 9; i >= 0; i-=2)
{
std::cout << "主线程:i=" <<i << std::endl;
Sleep(100);
}
th1.join();//join()函数写在这里输出是随机的
return 0;
}
输出:每次结果不一样
主线程:i=9
子线程:i=10
主线程:i=7
子线程:i=8
主线程:i=5
子线程:i=6
主线程:i=3
子线程:i=4
子线程:i=2
主线程:i=1
子线程:i=0
Mat是一种图像容器,是二维向量,灰度图的Mat一般存放< uchar >类型,RGB彩色图像一般存放< Vec3b > 类型。
三维向量ijk叉乘
| i j k |
| a1 b1 c1 |
| a2 b2 c2 |
=(b1c2-b2c1,c1a2-a1c2,a1b2-a2b1)
其他详见笔记本7月21日笔记
n阶矩阵A和B,AB=BA=。我们称B是A的逆矩阵,而A则被称为可逆矩阵。其中E为单位矩阵,也叫对角线矩阵。
可逆条件:|A|!=0
奇异矩阵:不可逆的矩阵。
非奇异矩阵:可逆的矩阵。
正交矩阵:ATA=E,正交矩阵的逆等于它的转置矩阵;
初等变换法
增广矩阵:在矩阵的右侧放置一个同阶的单位矩阵
待定系数法
解方程组
智能指针会在超出作用域后自行清理(从而消除对大多数内存泄漏的恐惧)。
共享指针是一种智能指针,它会对存在的指针实例数进行计数,并且仅在计数达到零时才清理内存。
与普通指针相比,共享指针重载了*、->、和==运算符;
不同的shared_ptr对象可以与相同的指针相关联,在内部使用引用奇数机制来实现这一点,每个对象在内部指向两个位置。
检查 shared_ptr 对象的引用计数
ptr.use_count();
所在库:#include < memory > 或者**#include< boost/shared_ptr.hpp>**
std::shared_ptr< Student >stu_ptr;//stu_ptr相当于一个NULL指针,做*ptr或者ptr->XX会出现异常
std::shared_ptr< Student > stu_ptr(new Student());
//使用std::make_shared类模板
std::shared_ptr stu_ptr2 = std::make_shared();
std::shared_ptr< Student>stu_ptr3(stu_ptr);
当共享指针 a 被赋值成 b 的时候,如果 a 原来是 NULL, 那么直接让 a 等于 b 并且让它们指向的东西的引用计数加 1; 如果 a 原来也指向某些东西的时候,如果 a 被赋值成 b, 那么原来 a 指向的东西的引用计数被减 1, 而新指向的对象的引用计数加 1。
std::shared_ptr< Student > stu_ptr(new Student());
std::shared_ptr< Student > stu_ptr4(new Student());
stu_ptr = stu_ptr4;//stu_ptr原先所指向的对象会被销毁,stu_ptr4所指对象引用计数+1
shared_ptr 的对象在构造之后,可以被赋予空值,此时使用的应该是 reset() 函数或者nullptr。
stu_ptr4.reset();//stu_ptr4 原先所指的对象的引用计数-1,并且 stu_ptr4 会变成 NULL。这里内存会被销毁
stu_ptr4 = nullptr;
shared_ptr 有两种类型转换的函数,一个是 static_pointer_cast, 一个是 dynamic_pointer_cast。
std::shared_ptr<A> ptra;
std::shared_ptr<B> ptrb(new B());
ptra = dynamic_pointer_cast<A>(ptrb);
std::shared_ptr<T> ptr(new T());
ptr.reset(new T()); // 原来所指的对象会被销毁
if(!ptr3)
std::cout<<"Yes, ptr3 is empty" << std::endl;
if(ptr3 == NULL)
std::cout<<"ptr3 is empty" << std::endl;
if(ptr3 == nullptr)
std::cout<<"ptr3 is empty" << std::endl;
if(ptr3==0)
std::cout<<"ptr3 is empty" << std::endl;
lambda表达式定义了一个匿名函数
语法:[ capture ] (params) opt->ret{ body;}; [捕获列表](参数表)
函数选项->返回值类型{函数体;}
auto f =[ ] (int a)->int{return a+1;}
auto f=[](int x)//C++11 中允许省略 lambda 表达式的返回值定义
{
for (int i = 0; i < x; i++)
{
std::cout << "线程使用lambda表达式作为可调用参数" << std::endl;
}
};
lambda 表达式在没有参数列表时,参数列表是可以省略的
auto f1 = [](){ return 1; };
auto f1 = []{ return 1; };//省略空参数表
lambda 表达式捕获列表
atoi()函数将数字格式的字符串转换为整数类型。例如,将字符串“12345”转换成数字12345。