C++:空的if语句

4
这是一个入门级问题,但我想知道是否有空if语句是良好的编程实践。
考虑以下代码:
void RabbitList::purge()
{
    if(head == NULL)
    {
        //cout << "Can't purge an empty colony!" << endl;
    }
    else
    {
        //Kill half the colony
        for(int amountToKill = (getColonySize()) / 2; amountToKill != 0;)
        {
            RabbitNode * curr = head;
            RabbitNode * trail = NULL;

            bool fiftyFiftyChance = randomGeneration(2);

            //If the random check succeeded but we're still on the head node
            if(fiftyFiftyChance == 1 && curr == head)
            {
                head = curr->next;
                delete curr;
                --size;
                --amountToKill;
            }
            //If the random check succeeded and we're beyond the head, but not on last node
            else if(fiftyFiftyChance == 1 && curr->next != NULL)
            {
                trail->next = curr->next;
                delete curr;
                --size;
                --amountToKill;
            }
            //If the random check succeeded, but we're on the last node
            else if(fiftyFiftyChance == 1)
            {
                trail->next = NULL;
                delete curr;
                --size;
                --amountToKill;
            }
            //If the random check failed
            else
            {
                trail = curr;
                curr = curr->next;
            }
        }
        cout << "Food shortage! Colony has been purged by half." << endl;
    }
}

正如您所看到的,第5行上的if语句目前已被注释掉; 这只是一个调试文本,我不想再向控制台发送任何反馈。我相信让if语句什么也不做会被认为是不好的实践。我知道我可以使用return;来解决这个问题。

但是,由于我的返回类型是void,它会给我一个错误。如果我的返回类型不是void呢?


2
这是一个风格问题,因此本质上是主观的。但是一个好的经验法则是永远不要在您的代码库中留下被注释掉的代码。 - Oliver Charlesworth
@Oli 谢谢你的回答。我正在自学,因此由于没有直接的指导,我仍然更喜欢问这些问题。 - Marcan
只是一件小事: 使用宏NULL已经被弃用,建议使用nullptr,请参阅https://dev59.com/b3M_5IYBdhLWcg3wq1CF和https://dev59.com/jGYr5IYBdhLWcg3wQYJa。 - kebs
甚至可以在for循环中加入“head”条件。 - Manuel
我曾经想过在这个问题上发布一个空的答案。 - Andrew
7个回答

6
即使您的返回类型为void,返回到那里也是合法的,而且由于if有花括号,至少这不是一个等待发生的错误。但是它不太美观,需要更多的阅读和理解工作。 您可以重新表述为:
if(head == NULL) // or if(!head)
    return;

....

这样做可以避免else的使用,而且剩余的代码现在都在函数内部而非嵌套作用域中,这是一个令人愉快的好处。

这是我的偏好。当你有一个简单的函数,并且一些条件会导致它什么也不做时,我喜欢在开始处检测并返回。这样我就避免了过多缩进,并且有一个原则,即如果我到达函数的结尾,那么它是成功的。 - paddy

5
对于单个分支,直接编写即可:
if (head != 0) {
    // whatever
}

对于多个分支,有时候留出一个空的第一分支可以简化后续条件语句:

if (head == 0) {
    // nothing to do
} else if (head->next == 0) {
    // whatever
} else {
    // whatever else
}

是的,您可以通过增加一层来编写最后一个:

if (head != 0) {
    if (head->next == 0) {
        // whatever
    } else {
        // whatever else
    }
}

但第一种形式更清晰,特别是当第二种形式最终会产生三到四个if层级时。

哦,还有

if (head == 0)
    return;

在编程中,有时候将函数转换成嵌套函数可能会很困难,因为它增加了一个额外的退出点。过去我很喜欢这种形式,但在过去几年中,我发现我经常要把它们移除。


2
我重写了你的函数,去除了重复和冗余部分。现在它变得更加简洁明了。
void RabbitList::purge()
{
    if(head == NULL) return;

    //Kill half the colony
    for(int amountToKill = (getColonySize()) / 2; amountToKill != 0;)
    {
        RabbitNode * curr = head;
        RabbitNode * trail = NULL;

        bool fiftyFiftyChance = randomGeneration(2);

        if(fiftyFiftyChance == 1 )
        {
            if( curr == head)
                head = curr->next;
            else
                trail->next = curr->next;

            delete curr;
            --size;
            --amountToKill;
        }
        else
        {
            trail = curr;
            curr = curr->next;
        }
    }
    cout << "Food shortage! Colony has been purged by half." << endl;
}

哇,太棒了。浏览您的代码让我意识到如何进行优化,从而使其更易读。谢谢。 - Marcan

2

我会摒弃if语句部分,直到第一个else,并用相反条件的if (head)替换它,这种情况下非常适合用来替代if-else。然而,整个函数需要多一个制表符的缩进。这时,变得更加推荐,但我自己倾向于早早解决检查问题,不让缩进变得复杂。

如果你需要从任何地方返回,可以使用return;


所以:if(head != NULL)和if(head)是一样的,对吗?那么if(head == NULL)和if(!head)也是一样的,对吗? - Marcan
@Marcan,是的,我更喜欢较短的形式。 - chris
谢谢。如果有一个检查两个条件的更长的语句呢?例如:if(mutantCount() > 0 && head)。还是写成if(mutantCount() > 0 && head != NULL) 更清晰明确? - Marcan
1
@Marcan,head应该和指针一样清晰。 - chris

2

我并不认为这是主观的。为什么要写死代码呢?这是初学者的明显标志。相反,只需检查您想要的条件,然后完成它:

if(!head)
   // stuff

1

正如@Oli在评论中所述,这是一个主观的样式问题。你有两个选择:

if (<something is true>) {
    // Do nothing
} else {
    // Some code goes here
}

或者

if (!<something is true>) {
    // Code goes here
}

我可以想象出一些情况,前者比后者更易读,特别是当条件相对复杂时。


0

我会放弃它。

但我会将记录虚拟化(std::cout并不总是有用)。

struct NullLogger : public Logger
{
    virtual void log(std::string const&) {}
};

// By default use the Null Logger
// But if you need to debug just pass a useful specialization of logging.
void RabbitList::purge(Logger const& logger = NullLogger())
{
    if(head == NULL)
    {
        logger.log("Can't purge an empty colony!");
    }
    else
    {

1
@Lieuwe:完整的胡说八道。 - Martin York

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接