有始有终的编码原则

文章讨论了在编程中遵循“谁分配谁释放”的资源管理原则,通过示例代码展示了如何改进文件操作以避免资源泄露和过度耦合。通过将文件处理的责任集中在一个函数中,代码变得更清晰,文件状态的管理也更有序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本情况

在程序员的修炼之道之中,说到:

这个建议能简单地应用到大多数场合。简单说就是,分配资源的函
数或对象,对释放资源应负有责任。

这其实就是我们常说的谁分配的就谁负责释放,这也是内存释放的一个原则,这一个原则,可以推而广之,就是谁分配的资源,就谁分配释放;这真是非常常用的东西,比如数据库存连接的分配与释放。

我写一个简单的例子说明这种情况,这一个例子就是单纯为了实现价格读出后,然后价格更改,再写入:

void Market::readCustomer()
{
    fopen_s(&m_pf, "test.txt", "r+");

    if (m_pf != nullptr)
    {
        CUSTOMER p = {0};
        fscanf(m_pf, "%s %d", p.name, &p.price);
        printf("%s %d\n", p.name, p.price);
    }
}

void Market::writeCustomer()
{
    if (m_pf != nullptr)
    {
        CUSTOMER p = { "zhangsan", m_money };
        fprintf(m_pf, "%s %d\n", p.name, p.price);
        printf("%s %d\n", p.name, p.price);
        fclose(m_pf);
        m_pf = nullptr;
    }
}

void Market::updateCustomer(int money)
{

    this->readCustomer();
    m_money = money;
    this->writeCustomer();

}

为了清楚其见,写下头文件的部分代码:

typedef struct Customer
{
    char name[10];
    int price;

}CUSTOMER;

private:
     FILE* m_pf;
     int m_money;

上面代码updateCustomer,看着是没问题的,但发现其耦合了变量 m_pf,从函数角度来看,的确是耦合这一个变量,不是一个好事;

后来加了些需要,要求100元以上,才更改价格,程序员,可能更改成下面这个样子:

void Market::updateCustomer(int money)
{

    this->readCustomer();
    m_money = money;
    if(m_money > 100)
    {
    	this->writeCustomer();
    }

}

运行代码,不一会,就提示打开的文件过多,原来,那些小于100的客户,只打开了文件的链接,没有关闭文件链接,与是可能更改如下:

void Market::updateCustomer(int money)
{

   this->readCustomer();
   m_money = money;
   if(m_money > 100)
   {
   	this->writeCustomer();
   }
   else
   {
     fclose(m_pf);
   }

}

现在问题是解决了,但是出现一个变量的三处耦合,最严重的是文件的状态变得混乱。

程序员修炼这样描述这种问题:

这个问题已修复——如果不考虑新的平衡,文件现在的确关闭了。
但是,这个修复方案意味着,三个例程因为共享变量m_pf耦合
在了一起,而且对文件何时是打开状态、何时是关闭状态的跟踪开始变
得混乱。我们正掉入一个陷阱,如果继续走这条路,情况将开始迅速恶
化。这是不平衡的!

那么,如果用有始有终的原则,则更改如下:

void Market::readCustomer(FILE *pf)
{
    if (pf != nullptr)
    {
        CUSTOMER p = {0};
        fscanf(pf, "%s %d", p.name, &p.price);
        printf("%s %d\n", p.name, p.price);
    }
}

void Market::writeCustomer(FILE *pf)
{
    if (pf != nullptr)
    {
        CUSTOMER p = { "zhangsan", m_money };
        fprintf(pf, "%s %d\n", p.name, p.price);
        printf("%s %d\n", p.name, p.price);
    }
}

void Market::updateCustomer(int money)
{   
    FILE *pf;
    fopen_s(&pf, "test.txt", "r+");
    this->readCustomer(pf);
    m_money = money;
    this->writeCustomer(pf);
    fclose(pf);
    pf = nullptr;
}

这样代码就清晰了很多:

我们修改了代码,将文件引用通过参数传进去,而不是在内部持有
引用[5]。现在,关于该文件的所有职责都在 updateCustomer例程中。
它打开文件,再(有始有终地)在返回之前关闭它。例程保持了文件使
用的平衡:打开和关闭在同一个位置,而且非常明显的是,每次对文件
的打开操作都有一个对应的关闭操作。重构还删除了一个丑陋的共享变
量。

总结

代码中时时处处都在遵守这一原则,代码才能清晰,代码才能简单。
image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员如山石

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

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

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

打赏作者

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

抵扣说明:

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

余额充值