C++ —— 防止进入无限循环的宏

这篇博客介绍了一种通过__COUNTER__宏或__LINE__宏来防止进入无限循环的方法。

该方法可以以一种透明的方式加入代码,在进行发行版编译的时候可以选择不对它进行编译。


原理

可能出现无限循环的地方,通常是一些依赖外部数据、外部脚本或者数据驱动的特定部分。由于外部数据的不可预测性,因此有必要对于无限循环的情况进行保护。

有一个实用的保护方法就是创建一个计数器,在每次循环的时候都进行+1,如果到达了某个极限的时候触发断言。

此时我们可以创建一个while_limit宏,它与普通的while循环差不多,唯一不同的就是有一个参数来定义循环次数的极限。当超过这个次数后,断言被触发。代码如下:

while_limit(node, 10000)
{
    // Do your work
    node = node->next;
}

while_limit宏的实现

while_limit宏的实现如下:


static bool while_assert( bool a )
{
    assert(a && "while_limit: exceeded iteration limit");
    return a;
}

#define UNIQUE_VAR(x) safety_limit ## X
#define _while_limit(a, b, c) \
    assert(b > 0 && "while_limit: limit is 0 or less"); \
    int UNIQUE_VAR(c) = b; \
    while (a && while_assert(--UNIQUE_VAR(c) >= 0 ))
#define while_limit(a, b) _while_limit(a, b, __COUNTER__)

上面的代码使用了assert断言来进行提示,比起无休止的等待对开发人员更加友好。并且如果开发人员选择忽略掉这个断言,则while_limit宏可以跳出这个循环而继续进行下面的流程。

__COUNTER__宏与唯一变量

由于while_limit可能会在多个地方展开,因此有必要给每一个地方的计数器都声明一个唯一变量。在代码中使用了__COUNTER__宏,这个宏展开为一个整数,初始化为0,每使用一次就+1。

因此我们可以使用##宏操作来进行唯一变量的创建,这个唯一变量可以用来跟踪循环次数。当第一次使用while_limit宏的时候,计数器变量名为safely_limit0,第二次则是safely_limit1,这就保证了不会产生多重定义的问题。

由于__COUNTER__宏在某些编译器里面编不过,因此实际上也可以使用另外的__LINE__宏来进行唯一变量名的创建。

后记

这篇博客介绍的方法属于宏的奇技淫巧了,有的时候看到这些方法也的确会感到耳目一新。做个记录就好,希望以后的路不要走偏……

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
桥接模式是一种结构型设计模式,它将抽象和实现分离,使它们可以独立地变化。桥接模式的核心思想是将一个大类或一组类分解成抽象和实现两个独立的维度,使它们可以独立地变化和扩展,同时通过桥接来将它们连接起来。 在C++中,桥接模式通常通过虚函数实现。抽象部分通过基类定义接口,而实现部分通过派生类实现具体的功能。通过将抽象部分的指针作为参数传递给实现部分的函数,就可以实现两个部分的连接。 下面是一个简单的桥接模式的C++示例: ```c++ class Implementor { public: virtual void operation() = 0; virtual ~Implementor() {} }; class ConcreteImplementorA : public Implementor { public: void operation() override { // 具体的实现A } }; class ConcreteImplementorB : public Implementor { public: void operation() override { // 具体的实现B } }; class Abstraction { public: Abstraction(Implementor* implementor) : m_implementor(implementor) {} virtual void operation() = 0; virtual ~Abstraction() {} protected: Implementor* m_implementor; }; class RefinedAbstraction : public Abstraction { public: RefinedAbstraction(Implementor* implementor) : Abstraction(implementor) {} void operation() override { m_implementor->operation(); // 其他操作 } }; int main() { Implementor* implementorA = new ConcreteImplementorA(); Implementor* implementorB = new ConcreteImplementorB(); Abstraction* abstractionA = new RefinedAbstraction(implementorA); Abstraction* abstractionB = new RefinedAbstraction(implementorB); abstractionA->operation(); abstractionB->operation(); delete abstractionA; delete abstractionB; delete implementorA; delete implementorB; return 0; } ``` 在上面的示例中,Implementor是实现部分的抽象基类,ConcreteImplementorA和ConcreteImplementorB是具体的实现类。Abstraction是抽象部分的基类,RefinedAbstraction是抽象部分的具体实现类。在main函数中,我们创建了不同的Implementor和Abstraction对象,并通过它们来完成不同的操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值