异常处理
1.异常概念
异常运行期间发生的错误。编译的时候没有错,语法是正确的,但是逻辑出现了问题
常见异常如 数组越界, 除0报错,申请内存空间出错。
程序出现错误,如果没有处理,就会停止运行
#include <iostream>
#include <list>
using namespace std;
int main()
{
string s="abc"; //下标到2
s.at(3);
cout<<"main方法"<<endl;
}
2.处理异常的方式:
解决异常:
处理了 try,,,catch
抛出异常 throw
exception是所有异常的基类。
#include <iostream>
#include <list>
using namespace std;
int main()
{
string s="abc"; //下标到2
try{
s.at(3);
cout<<"hello"<<endl; //上一行出现错误,就不会运行输出
}catch(exception e){
//解决办法
cout<<"问题已解决"<<endl;
}
cout<<"main方法"<<endl;
}
c++标准异常库
#include <iostream>
using namespace std;
int main()
{
double a=2.5,b=0;
string name="zhangsan";
try{
if(b==0)
throw -1;
cout<<a/b<<endl; //inf
}
catch(int e){
cout<<"没事可以通过"<<endl;
}
}
catch可以捕获任意类型的异常。如下发可以捕获throw的int 和 char类型异常
#include <iostream>
using namespace std;
int main()
{
double a=2.5,b=1;
string name="zhangsan";
string str;
try{
if(b==0)
throw -1;
if("zhangsan"==name)
throw 'e';
cout<<a/b<<endl; //inf
}
catch(int e){
cout<<"没事可以通过"<<endl;
}
catch(char e){
cout<<"张三上线"<<endl;
}
}
继承异常基类。
#include <iostream>
using namespace std;
class MyException:public exception{ //自己创建的类 作为异常类
public:
const char * what() const throw(){
return "除数不能为0";
}
};
double division(const int & a,const int & b){
if(b==0)
throw MyException();
return a/b;
}
int main()
{
double n=1.5,m=0;
try{
division(n,m);
}catch(MyException ess){
cout<<ess.what()<<endl;
}
cout<<"-----------"<<endl;
}
4.多重捕获
为了增加错误捕获的概率,catch捕获的异常可以写多个.
直接用基类except都可以捕获到错误,但看不出具体什么错误。
可以用多重捕获,增加异常可以正常捕获的概率。但如果都没有catch捕获到,程序还是会停止。
#include <stdexcept> //C++异常处理标准头文件
#include <iostream>
#include <stdexcept> //异常处理头文件
using namespace std;
int main()
{
string s="abc";
try{
s.at(4);
}catch(const out_of_range e){
cout<<e.what();
}
catch(exception e){
cout<<e.what();
}
}
exception只能处理已经定义的异常。 catch(...)可以处理任意的
注意事项:把具体的异常类捕获放在前面,基类放在后面
#include <iostream>
#include <stdexcept> //异常处理头文件
using namespace std;
int main()
{
string s="abc";
try{
throw("hello");
cout<<s.at(2)<<endl;
}catch(const out_of_range e){
cout<<e.what()<<endl;
}
catch(exception e){
cout<<e.what();
}
catch(...){
cout<<"。。。"<<endl;
}
cout<<"main_end"<<endl;
}
智能指针
new出来的对象需要手动销毁,如果忘记销毁就会造成内存泄漏。c++98之后引入了智能指针。是堆内存对象自动回收智能指针是也是类模板,是在栈上创建对象。new()出来的对象指针在栈上。智能指针对象可以对这些普通指针进行管理。当智能指针对象的生命周期结束。就会在析构函数中释放掉管理对象的内存,防止内存泄漏。
auto_ptr 现在不推荐使用
unique_ptr 唯一指针
shared_ptr 共享指针
weak_ptr 虚指针tt
auto_pt
auto_ptr<Test> ptr(t) 意思:
<Test>管理的类的名字
ptr智能智能名字
t 需要传入内存对象地址
#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
string str;
public:
Test(string s):str(s){
cout<<str<<"创建了"<<endl;
}
~Test(){
cout<<str<<"销毁了"<<endl;
}
};
int main()
{
Test * t=new Test("A");
auto_ptr<Test> ptr(t);
//推荐下面这种
auto_ptr<Test> ptr2(new Test("B"));
}
问题:在复制语义中出现控制权转移问题 如赋值。拷贝函数
#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
string str;
public:
Test(string s):str(s){
cout<<str<<"创建了"<<endl;
}
~Test(){
cout<<str<<"销毁了"<<endl;
}
void show(){
cout<<"成员值:"<<str<<endl;
}
};
int main()
{
Test * t=new Test("A");
auto_ptr<Test> ptr1(t);
//get()方法可以得到对象地址
cout<<ptr1.get()<<" "<<t<<endl; //0x12417d8 0x12417d8
//推荐下面这种
auto_ptr<Test> ptr2(new Test("B"));
ptr2.get()->show(); //B
//重写管理新的对象 会销毁原来的对象
ptr2.reset(new Test("C"));
//不能用普通指针赋值
auto_ptr<Test> ptr3=ptr1; //拷贝
auto_ptr<Test> ptr4(ptr2); //显示拷贝
cout<<ptr1.get()<<endl; //0
cout<<ptr2.get()<<endl; //0
cout<<ptr3.get()<<endl; //0xeb17d8
cout<<ptr4.get()<<endl; //0xeb2a08
}
unique_ptr(掌握)
#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
string str;
public:
Test(string s):str(s){
cout<<str<<"创建了"<<endl;
}
~Test(){
cout<<str<<"销毁了"<<endl;
}
void show(){
cout<<"成员值:"<<str<<endl;
}
};
int main()
{
Test * t=new Test("A");
unique_ptr<Test> ptr1(t);
//get()方法可以得到对象地址
cout<<ptr1.get()<<" "<<t<<endl; //0x12417d8 0x12417d8
//推荐下面这种
unique_ptr<Test> ptr2(new Test("B"));
ptr2.get()->show(); //B
//重写管理新的对象 会销毁原来的对象
ptr2.reset(new Test("C"));
//不能用普通指针直接赋值
// unique_ptr<Test> ptr3=ptr1; //不允许隐身拷贝
// unique_ptr<Test> ptr4(ptr2); //不允许显示拷贝
// unique_ptr<Test> ptr5;
// ptr5=ptr1; //不允许赋值
cout<<ptr1.get()<<endl; //0
cout<<ptr2.get()<<endl; //0
}
shared_ptr(掌握)
#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
string str;
public:
Test(string s):str(s){
cout<<str<<"创建了"<<endl;
}
~Test(){
cout<<str<<"销毁了"<<endl;
}
void show(){
cout<<"成员值:"<<str<<endl;
}
};
int main()
{
Test * t=new Test("A");
shared_ptr<Test> ptr2;
{
shared_ptr<Test> ptr1(t);
ptr2=ptr1; //**
cout<<"1):"<<ptr1.use_count()<<endl;
//不能用普通指针赋值
shared_ptr<Test> ptr3=ptr1;
cout<<"2):"<<ptr1.use_count()<<" "<<ptr3.use_count()<<endl;
shared_ptr<Test> ptr4(ptr1);
cout<<"3):"<<ptr1.use_count()<<" "<<ptr3.use_count()
<<" "<<ptr4.use_count()<<endl;
shared_ptr<Test> ptr5;
ptr5=ptr1;
cout<<"3):"<<ptr1.use_count()<<" "<<ptr3.use_count()<<" "
<<ptr4.use_count()<<" "<<ptr5.use_count()<<endl;
ptr5.reset(); //ptr5释放了自己的管理权。但资源还被其他智能指针共享
cout<<"end):"<<ptr1.use_count()<<" "<<ptr3.use_count()<<" "
<<ptr4.use_count()<<" "<<ptr5.use_count()<<endl;
}
cout<<ptr2.use_count()<<endl;
cout<<"------------";
}
/*
A创建了
1):2
2):3 3
3):4 4 4
3):5 5 5 5
end):4 4 4 0
1
------------A销毁了
*/
shared_ptr<Test> ptr9=make_shared<Test>("B");
特点:性能更好 更加安全
weak_ptr
不实际控制对象生命周期,也就不会增减use_count()
协助shared_ptrl来使用的
解决shared_ptrl的循环引用的问题
#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
string str;
public:
Test(string s):str(s){
cout<<str<<"创建了"<<endl;
}
~Test(){
cout<<str<<"销毁了"<<endl;
}
void show(){
cout<<"成员值:"<<str<<endl;
}
};
int main()
{
// weak_ptr<Test> ptr9=make_shared<Test>("B");
shared_ptr<Test> ptr1(new Test("A"));
weak_ptr<Test> ptr2;
{
ptr2=ptr1; //**
cout<<"1):"<<ptr1.use_count()<<endl;
//不能用普通指针赋值
weak_ptr<Test> ptr3=ptr1;
cout<<"2):"<<ptr1.use_count()<<" "<<ptr3.use_count()<<endl;
weak_ptr<Test> ptr4(ptr1);
cout<<"3):"<<ptr1.use_count()<<" "<<ptr3.use_count()
<<" "<<ptr4.use_count()<<endl;
weak_ptr<Test> ptr5;
ptr5=ptr1;
cout<<"3):"<<ptr1.use_count()<<" "<<ptr3.use_count()<<" "
<<ptr4.use_count()<<" "<<ptr5.use_count()<<endl;
ptr5.reset();
cout<<"end):"<<ptr1.use_count()<<" "<<ptr3.use_count()<<" "
<<ptr4.use_count()<<" "<<ptr5.use_count()<<endl;
}
cout<<ptr2.use_count()<<endl;
cout<<"------------";
}
nullptr
#define NULL 0
c++11中用来代替NULL
#include <iostream>
#include <memory>
using namespace std;
void func(int){
cout<<"n"<<endl;
}
void func(char *){
cout<<"char *"<<endl;
}
int main()
{
char *c=NULL;
func(c); //char *
func(NULL); //n
func(nullptr);//char *
}
其他内容:
类型推导
auto不能用于参数。也不能支持数组和表达式
#include <iostream>
using namespace std;
int main()
{
auto i=6;
cout<<i<<endl;
auto i2=new auto(18);
cout<<*i2<<endl;
int * i3=new int(18);
cout<<*i3<<endl;
}
进制输出
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
//默认10进制
cout<<showbase; //没有括号
cout<<oct; //8进制
cout<<11<<endl; //013
cout<<hex<<15<<endl; //0xf
cout<<dec<<6<<endl; //6
cout<<noshowbase;
}
设置场宽
#include <iomanip>
#include <iostream>
#include <iomanip>
using namespace std;
int main()3
{
cout<<setw(5)<<7<<endl;
cout<<"#########"<<endl;
cout<<setw(5)<<setfill('*')<<7<<endl; //默认右对齐
}
字符串流
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
//int到string
stringstream ss;
int i=1234;
ss<<i;
string s=ss.str();
cout<<s<<endl;
s.append("hello");
cout<<s<<endl;
//string到int
string s2="1234567";
istringstream iss(s2);
iss>>i;
cout<<i<<endl;
cout<<++i<<endl;
}