【问题标题】:while loop with comma operator verses duplicate code verses “break;”带有逗号运算符的while循环与重复代码与“break;”
【发布时间】:2016-06-26 23:46:45
【问题描述】:

在阅读了关于 C/C++ 中逗号运算符的精彩回答(What does the comma operator do - 我使用了相同的示例代码)之后,我想知道哪种方式是实现 while 循环的最易读、最易于维护和首选的方式。特别是一个while循环,其条件取决于操作或计算,并且条件第一次可能为假(如果循环总是至少通过一次那么do-while将起作用很好)。

逗号版本是最喜欢的吗? (每个答案如何,其余的可以通过相应的投票来投票?)

简单实现

此代码有重复的语句,(很可能)必须始终相同。

string s;
read_string(s);     // first call to set up the condition
while(s.len() > 5)  // might be false the first pass
{
   //do something
   read_string(s);  // subsequent identical code to update the condition
}

使用break实现

string s;
while(1)                  // this looks like trouble
{
   read_string(s);
   if(s.len() > 5) break; // hmmm, where else might this loop exit
   //do something
}

使用逗号实现

string s;
while( read_string(s), s.len() > 5 ) 
{
   //do something
}

【问题讨论】:

  • 使用do-while模式,在开始执行read_string,在最后测试条件。
  • 你们俩都忘记了“做某事”,我猜应该在read_string之后执行,并且只有条件通过。
  • @Cody Gray:我不清楚吗?如果第一次条件中的代码为假(并且循环不应该进入),这不会处理这种情况。
  • 我通常不喜欢逗号运算符的小“技巧”​​,但在这种情况下,鉴于read_string 的设置方式,我会投票给#3。 while( reading a line succeeds ) { do something with the line } 模式是一种非常强大、可读、自然且常见的模式,值得坚持使用。但是,更值得重写 read_string 函数以便可以直接使用它的返回值。
  • 投票重新开放。虽然这在某种程度上确实涉及到意见,但对于如何使这样的代码具有可读性的问题有足够的事实基础,因此这是一个有价值的问题,可以产生有意义的答案。

标签: c++ c while-loop break comma-operator


【解决方案1】:

第四个选项对我来说似乎更好:

string s;
while( read_string(s) && s.len() > 5 ) 
{
   //do something
}

【讨论】:

  • @Michael read_string 不应是 void 函数。如果您正在执行读取操作,您应该返回一个布尔值,以便您判断读取是否成功。
  • 如果read_string返回void,那么while( read_string(s), s.len() > 5 )更好。
  • read_string() 是一个例子,我的意思是准备条件所需的任何操作。它可能返回 true、false、0、1 或 void...
  • read_string 应该返回读取的字节数,并且您已完成while(read_string(s) > 5)。我认为最好的设计是:整个问题都存在,因为read_string 是 IMO 设计不佳。
  • @Michael,很难为假设的用例提出通用解决方案。如果执行准备工作的函数返回状态,我认为这是一个更好的设计。
【解决方案2】:

以上都不是。我看到了几个选项。它们之间的选择取决于您的实际限制。

一种可能性是你有一个字符串应该总是有一些最小长度。如果是这种情况,您可以定义 体现该要求的类:

template <size_t min>
class MinString{
    std::string data;
public:
    friend std::istream &operator>>(std::istream &is, MinString &m) {
        std::string s;
        read_string(is, s); // rewrite read_string to take an istream & as a parameter
        if (s.length() >= min)
            m.data = s;
        else
            is.setstate(std::ios::failbit);
        return is;
    }

    operator std::string() { return data; }

    // depending on needs, maybe more here such as assignment operator
    // and/or ctor that enforce the same minimum length requirement

};

这导致代码如下:

Minstring<5> s;
while (infile >> s)
    process(s);

另一种可能是你有正常的字符串,但在某些情况下你需要做一个必须在 至少 5 个字符。在这种情况下,强制执行应该在函数中而不是类型中。

bool read_string_min(std::string &s, size_t min_len) { 
    read_string(s);
    return s.length() >= min_len;
}

同样,有了这个循环可以简单而干净:

while (read_string_min(s, 5))
    process(s);

也可以只编写一个函数来返回读取的长度,并保留执行最小值 while 循环中的长度:

while (read_string(s) > 5)
    process(s);

有些人喜欢这个,因为它更符合单一职责原则。 IMO,“读取至少 5 个字符的字符串”完全可以作为一项单一职责,所以我觉得它充其量只是一个弱论点(但即使这种设计仍然可以很容易地干净地编写代码)。

总结:任何输入的东西都应该隐式或显式地提供某种方式来验证它是否正确读取了输入。只是试图读取一些输入但没有提供成功/失败指示的东西只是一个糟糕的设计(正是你的read_string 设计中的明显失败导致了你遇到的问题)。

【讨论】:

    猜你喜欢
    • 2017-05-27
    • 2014-06-16
    • 2013-12-02
    • 2015-09-24
    • 2014-03-23
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    • 2013-05-27
    相关资源
    最近更新 更多