罪恶克星 发表于 2026-2-11 18:23:56

C++ 非常

1.C语言处理处罚错误

1. 停止步伐,如assert,缺陷:用户难以担当。如发生内存错误,除0错误时就会停止步伐。
2. 返回错误码,缺陷:须要步伐员自己去查找对应的错误。如体系的很多库的接口函数都是通过把错误码放到errno中,表现错误
实际中C语言根本都是使用返回错误码的方式处理处罚错误,部门环境下使用停止步伐处理处罚非常严峻的错误
2.C++非常

概念

非常是一种处理处罚错误的方式,当一个函数发现自己无法处理处罚的错误时就可以抛出非常,让函数的直接或间接的调用者处理处罚这个错误。
throw: 这是通过使用 throw 关键字来抛出非常。
catch: catch 关键字用于捕获非常,可以有多个catch举行捕获。
try: try 块中的代码标识将被激活的特定非常,它反面通常跟着一个或多个 catch 块。

try
{
        func();
}
catch (ExceptionName e1)
{
        // catch 块
}
catch (ExceptionName e2)
{
        // catch 块
}
catch (ExceptionName eN)
{
        // catch 块
}非常抛出和捕获

非常的抛出和匹配原则
1. 非常是通过抛出对象,该对象的范例决定了应该匹配哪个catch的处理处罚代码。
2. 被选中的处理处罚代码是调用链中与该对象范例匹配,且离抛出非常位置近来的那一个。
3. 抛出非常对象后,会天生一个非常对象的拷贝,由于抛出的非常对象大概是一个暂时对象,以是会天生一个拷贝对象,这个拷贝的暂时对象会在被catch以后烧毁。(这里的处理处罚雷同于函数的传值返回)
4. catch(...)可以捕获恣意范例的非常,标题是不知道非常错误是什么。
5. 固然捕获的匹配是完全匹配的(int只能匹配int,不能隐式转换匹配其他范例 )实际中抛出和捕获的匹配原则有个例外,并不都是范例完全匹配,可以抛出的派生类对象,使用基类捕获。

double Division(int a, int b)
{
        // 当b == 0时抛出异常
        if (b == 0)

                throw "Division by zero condition!";
        else
                return ((double)a / (double)b);
        cout << "111" << endl;
}
void Func()
{
        int len, time;
        cin >> len >> time;
        try
        {
                cout << Division(len, time) << endl;
        }
    //匹配最近的
        catch (const char* errmsg)
        {
                cout <<"Func:" << errmsg << endl;
        }
    //执行catch后面程序
        cout << "111" << endl;
}
int main()
{
        try
        {
                Func();
        }
        catch (const char* errmsg)
        {
          cout << "main:" << errmsg << endl;
        }
        catch (...)
        {
                cout << "main:"<<"unkown exception" << endl;
        }
    //执行catch后面程序
        cout << "111" << endl;
        return 0;
       
}在函数调用链中非常栈睁开匹配原则
1. 起首查抄throw自己是否在try块内部,假如是再查找匹配的catch语句。假如有匹配的,则调到catch的地方举行处理处罚。
2. 没有匹配的catch则退出当前函数栈,继承在调用函数的栈中举行查找匹配的catch。
3. 假如到达main函数的栈,仍旧没有匹配的,则停止步伐。(上述这个沿着调用链查找匹配的catch子句的过程称为栈睁开。)以是实际中我们末了都要加一个catch(...)捕获恣意范例的非常,否则当有非常没捕获,步伐就会直接停止。
4. 找到匹配的catch子句并处理处罚以后,会继承沿着catch子句反面继承实行。
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvNjMyYjJhYjE4NzM3NDJlYzljZGRiMzRkYjcyNzBkZTkucG5n
https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvMGUyMjU3OTlmZjBiNDhjZmJiMzQ2NmFhZjExOTk5ZjMucG5n
非常的重新抛出

有大概单个的catch不能完全处理处罚一个非常,在举行一些校正处理处罚以后,渴望再交给更外层的调用链函数来处理处罚,catch则可以通过重新抛出将非常转达给更上层的函数举行处理处罚。

double Division(int a, int b)
{
        // 当b == 0时抛出异常
        if (b == 0)
        {
                throw "Division by zero condition!";
        }
        return (double)a / (double)b;
}
void Func()
{
        // 这里可以看到如果发生除0错误抛出异常,另外下面的array没有得到释放。
        // 所以这里捕获异常后并不处理异常,异常还是交给外面处理,这里捕获了再
        // 重新抛出去。
        int* array = new int;
        try {
                int len, time;
                cin >> len >> time;
                cout << Division(len, time) << endl;
        }
        //先释放array再抛出异常
        catch (...)
        {
                cout << "delete []" << array << endl;
                delete[] array;
                throw;
        }
        // ...
        cout << "delete []" << array << endl;
        delete[] array;
}
int main()
{
        try
        {
                Func();
        }
        catch (const char* errmsg)
        {
                cout << errmsg << endl;
        }
        return 0;
}https://dis.qidao123.com/imgproxy/aHR0cHM6Ly9pLWJsb2cuY3NkbmltZy5jbi9kaXJlY3QvZjU3OGQzNGNlMmI4NDg2OGFhZGMzYTU2NGVmNTcwOWYucG5n
这种标题以后,我们一样平常用智能指针举行办理。
非常安全

1.构造函数完成对象的构造和初始化,最好不要在构造函数中抛出非常,否则大概导致对象不完备或没有完全初始化。
2.析构函数紧张完成资源的整理,最好不要在析构函数内抛出非常,否则大概导致资源走漏(内存走漏、句柄未关闭等)
3.C++中非经常常会导致资源走漏的标题,好比在new和delete中抛出了非常,导致内存泄
漏。
非通例范

1. 非通例格分析的目的是为了让函数使用者知道该函数大概抛出的非常有哪些。 可以在函数的反面接throw(范例),列出这个函数大概投掷的全部非常范例。
2. 函数的反面接throw(),表现函数不抛非常。
3. 若无非常接口声明,则此函数可以投掷任何范例的非常。

// 这里表示这个函数会抛出A/B/C/D中的某种类型的异常
void fun() throw(A,B,C,D);
// 这里表示这个函数只会抛出bad_alloc的异常
void* operator new (std::size_t size) throw (std::bad_alloc);
// 这里表示这个函数不会抛出异常
void* operator delete (std::size_t size, void* ptr) throw();
// C++11 中新增的noexcept,表示不会抛异常
thread() noexcept;
thread (thread&& x) noexcept;自界说非常体系

假如我们恣意抛出非常的范例,表面必须有对应匹配的catch,那么有没有一种同一的方法吸收非常。我们一样平常界说一个基类包罗虚函数。抛非常时返回对应的派生类,在派生类中重写虚函数包罗这种非常的干系信息,表面用基类吸收,实现多态调用虚函数获取非常。

//基类
class Exception
{
public:
        Exception(const string& errmsg, int id)
                :_errmsg(errmsg)
                , _id(id)
        {}
        virtual string what() const
        {
                return _errmsg;
        }
protected:
        string _errmsg;
        int _id;
};
//生成不同的派生类,包含不同的异常信息
class SqlException : public Exception
{
public:
        SqlException(const string& errmsg, int id, const string& sql)
                :Exception(errmsg, id)
                , _sql(sql)
        {}
        virtual string what() const
        {
                string str = "SqlException:";
                str += _errmsg;
                str += "->";
                str += _sql;
                return str;
        }
private:
        const string _sql;
};
class CacheException : public Exception
{
public:
        CacheException(const string& errmsg, int id)
                :Exception(errmsg, id)
        {}
        virtual string what() const
        {
                string str = "CacheException:";
                str += _errmsg;
                return str;
        }
};
class HttpServerException : public Exception
{
public:
        HttpServerException(const string& errmsg, int id, const string& type)
                :Exception(errmsg, id)
                , _type(type)
        {}
        virtual string what() const
        {
                string str = "HttpServerException:";
                str += _type;
                str += ":";
                str += _errmsg;
                return str;
        }
private:
        const string _type;
};
void SQLMgr()
{
        srand(time(0));
        if (rand() % 7 == 0)
        {
                throw SqlException("权限不足", 100, "select * from name = '张三'");
        }
        //throw "xxxxxx";
}
void CacheMgr()
{
        srand(time(0));
        if (rand() % 5 == 0)
        {
                throw CacheException("权限不足", 100);
        }
        else if (rand() % 6 == 0)
        {
                throw CacheException("数据不存在", 101);
        }
        SQLMgr();
}
void HttpServer()
{
        // ...
        srand(time(0));
        if (rand() % 3 == 0)
        {
                throw HttpServerException("请求资源不存在", 100, "get");
        }
        else if (rand() % 4 == 0)
        {
                throw HttpServerException("权限不足", 101, "post");
        }
        CacheMgr();
}
int main()
{
        while (1)
        {
                this_thread::sleep_for(chrono::seconds(1));
                try {
                        HttpServer();
                }
                catch (const Exception& e) // 这里捕获基类对象就可以
                {
                        // 多态
                        cout << e.what() << endl;
                }
                catch (...)
                {
                        cout << "Unkown Exception" << endl;
                }
        }
        return 0;
}C++非常的优缺点:

C++非常的长处:
1. 非常对象界说好了,相比错误码的方式可以清楚准确的展示堕落误的各种信息.
2. 返回错误码的传统方式有个很大的标题就是,在函数调用链中,深层的函数返回了错误,那么我们得层层返回错误,最外层才气拿到错误。
3.部门函数使用非常更利益置处罚,好比构造函数没有返回值,不方便使用错误码方式处理处罚。
C++非常的缺点:
1. 非常会导致步伐的实行流乱跳,而且非常的紊乱,而且是运行时堕落抛非常就会乱跳。
2. 非常会有一些性能的开销。固然在当代硬件速率很快的环境下,这个影响根本忽略不计。
3.非常非常容易导致内存走漏、死锁等非常安全标题。
4. 非常只管规范使用,否则结果不堪假想。










免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金
页: [1]
查看完整版本: C++ 非常