C++基础::自制异常定位器

我们经常会有这样的需求,异常或错误(又或者内存泄露时)发生时,如何进行快速定位,定位到文件一级、定位到函数一级、乃至定位到异常出现的行号一级。如此高大上的需求,只需要了解C++ preprocessor内置的一些宏定义如__FILE__(文件名),__LINE__(行号),以及boost\current_function.hpp 中的BOOST_CURRENT_FUNCTION(函数名),将这些宏定义以参数的形式传递给一个异常类,再施以一定的封装,便可轻松实现对异常出现位置的捕捉。

#include <exception>
#include <boost\shared_ptr.hpp>
#include <sstream>

using namespace std;

class Error :public exception
{
public:
    Error(const string& file, long line, 
                const string& func, const string& msg);
    const char* what() const;           // 重写父类的what函数
private:
    string format(const string& file, long line,
                const string& func, const string& msg);
    boost::shared_ptr<string> _msg;   
                    // 操作_msg, 如同操作一个string* 
};

Error::Error(const string& file, long line, 
            const string& func, const string& msg)
{
    _msg = boost::shared_ptr<string>(new string(
            format(file, line, func, msg)));
}

string format(const string& file, long line, 
            const string& func, const string& msg)
{
    ostringstream oss;          // #include <sstream>
    oss << func << ":\n";
    oss << file << "(" << line << ").\n" << msg;
    return oss.str();
}

const char* Error::what() const
{
    return _msg.c_str();
}

客户端程序:

double divide(double x, double y)
{
    if (y == 0.)
        throw Error(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, "除数不能为0");    // #include <boost\current_function.hpp>
    return x/y;
}
int main(int, char**)
{
    try
    {
        divide(1., 0.);
    }
    catch(exception& e)
    {
        cout << e.what() << endl;
    }
}

C++预处理器也提供了如下的宏定义:

__DATE__
__TIME__

当然一种更常规的做法,利用宏定义(也只能用宏,而不可使用inline 内联函数取代,不由分说的原样替换虽然臭名昭著,却也有时非它不可)的原样替换的特性,对此做进一步的封装,避免显式传参的动作:

#define FAIL(msg)\
    std::ostringstream oss; \
    oss << msg; \
    throw Error(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, 
            oss.str());

#define ASSERT(predicate, msg)\
    if (!(predicate)) \
    {    \
        FAIL(msg);\
    }

这样客户端代码就可改写为:

double divide(double x, double y)
{
    if (y == 0.)
    {
        FAIL("除数不能为0");    
            // 这一点要尤其注意,一定要将FAIL放在if判断的括号内部 
            // 如果不这样做的话,if 默认后面的一条语句作为你if判断成立时,要执行的动作
            // 这样FAIL宏原样替换的话,就无法识别oss << msg; 中的oss了
    }
    return x / y;
}

因为FAIL宏执行的动作是throw抛异常,如果不对之进行捕获的话,将由编译器进行捕获:

int main(int, char**)
{
    double x = 1., y = 0.;
    divide(x, y);
    return 0;
}

编译器将弹出如下窗口:


这里写图片描述

int main(int, char**)
{
    try
    {
        double x = 1., y = 0.;
        divide(x, y);
    }
    catch(exception& e)
    {
        cout << e.what() << endl;
    }
    return 0;
}

或者我们使用断言的方式:

int main(int, char**)
{

    try
    {
        double x = 1., y = 0.;
        ASSERT(y != 0., "除数不能为0");
    }
    catch(exception& e)
    {
        cout << e.what() << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值