使用花括号分隔我想在 C++ 中多次使用的变量

Using curly braces to segregate a variable that I want to use multiple times in C++

在下面的代码中,我有一个 while 语句用于确保输入的字符串少于 10 个字符。我已经声明了一个名为 contbool,我用它来告诉 while 循环在满足我的条件后停止。

#include "stdafx.h"
#include <iostream>
#include <string>

int main()
{
    using namespace std;

    cout << "Enter a string less than 10 characters long: ";

    string teststring;

    {
        bool cont(false);

        //if input is 10 or more characters, ask for input again until it is less
        while (!cont)
        {
            getline(cin, teststring);

            if (teststring.length() >= 10)
            {
                cout << "Too long, try again: ";
            }
            else
            {
                cout << "Thank you.\n\n";
                cont = true;
            }

        }
    }

    return 0;
}

如您所见,我使用一组 {} 将代码分开,在这些大括号内为 cont 变量提供局部范围。我这样做是为了如果我想再次使用那个变量名,我可以重新声明它,当我用完它时,它就被销毁了。

这是可以接受的做法吗?或者有更好的方法来完成我所做的事情吗?我承认在这个特定的、基本的场景中,条件很简单,几乎没有必要,但我可能想在未来对更复杂的循环这样做。

一般情况下?是的。这个不错。

在这个具体案例中?不,没必要。您不会 再次使用该名称,并且在这个简单的代码中您不会这样做。所以这只是噪音。

看……这是平衡。

我发现自己在执行多个相关 SQL 语句的函数中经常这样做。每次我可能会用一个名为 ssstd::stringstream 来构建它。当然,我可以给每一个都起一个不同的名字,但它完全可以防止错误,将每个语句生成器保留在自己的范围内。

当你使用锁守卫之类的东西时,这也是一种非常常用的技术。

这是一种可以接受的做法,并且完全按照您说的去做。然而,它很少被使用,因为在小函数中,在函数顶级范围内使用 cont 变量是明确的,因此是可以接受的。如果您觉得需要在更大的函数中分离范围,通常首选创建另一个具有明确名称的函数。

您可以将这些大括号视为只调用一次的无名函数。如果您发现自己经常使用它,也许您应该给它起一个自己的名字。

另一种选择是重写循环以不需要 cont 变量,例如:

string teststring;
do
{
    cout << "Enter a string less than 10 characters long: ";
    getline(cin, teststring);
} while (teststring.length() >= 10);

cout << "Thank you.\n\n";

但这并不总是可行的,尤其是当您需要根据停止条件输出不同的消息时。

这显然是一个玩具箱,但这是一个很好的做法,'stand-alone' 积木就是为了这个目的。 我碰巧相信它们是构建长函数的更好方法,而不是将其分解为(在许多情况下)没有单独目的的成员。

在这种情况下,您可以提供更快、更清晰、更安全的程序,特别是如果有注释(可能是一行)介绍每个块。

但是在这种情况下,您可以考虑:

    for ( bool cont(false);!cont;)

效果相同。 for(.;.;.) 语句中声明的变量仅限于该语句的范围。

在这种情况下,您可以通过以下方式躲避整个变量:

    for(;;) //<--- Canonical formulation for 'infinite' loop.
    {
        getline(cin, teststring);

        if (teststring.length() >= 10)
        {
            cout << "Too long, try again: ";
        }
        else
        {
            cout << "Thank you.\n\n";
            break; //<--- Escapes the loop.
        }

    }

脚注(回应评论):

您应该将 for 循环视为 while 循环上的 'syntactic sugar'。这在他们的表现等方面没有什么不同,只需选择阅读最好的那个。 for(;cond;) 看起来很有趣。

break 可能会有微小的(微小的)性能优势,但我碰巧认为它在许多情况下实际上更简单且更具可读性。

如果代码更复杂,可能会有更多 'loop end' 代码,因此它变成:

for(bool cont(false);!cont;) {

    //Complex code with multiple 'exit' conditions...

    if(!cont) {
        //Go round again code that won't fit nicely in last term of for loop...
    }
}

而使用 break 只会让 'swift exit' 更容易理解。 他们没有(广泛地)被认为拥有 goto 的 'bad karma',因为他们 'go to' 是一个非常明确定义的执行点。

是的,没关系,如果您有充分的理由重新使用变量。锁守卫是我自己代码中最常见的用法,Lightness 的回答 std::stringstream ss 中给出了示例。基本上只要选择不同的变量名感觉更尴尬,就可以这样做。例如。如果您在代码中编写 lock1lock2lock3、...。

然而,更可接受的做法是将长函数体视为代码异味,并将它们重构为自己的函数。例如

...
string teststring;

{
    bool cont(false);
    //10 lines of code to handle the foo scenario
}
{
    bool cont(false);
    //15 lines of code to handle the bar scenario
}
...

这可以通过重构来更好地处理,如下所示:

...
string teststring;
foo(teststring);
bar(teststring);
...

void foo(string &teststring){
bool cont(false);
//10 lines of code
}

void bar(string &teststring){
bool cont(false);
//15 lines of code
}