限制变量范围的利弊

Pro and cons of restrict the scope of variable

本文关键字:范围 变量      更新时间:2023-10-16

摘自《C++编程语言4版》一书,作者喜欢限制变量的作用域。它位于"3.2.1.3 初始化容器"一章中

代码为:

Vector read(istream& is)
{
    Vector v;
    for (double d; is>>d;) // read floating-point values into d
    v.push_back(d); // add d to v
    return v;
}

他说

我使用了for语句而不是更传统的语句 while-语句,以将 d 的作用域限制在循环中。

这样做有什么好处?

限制范围意味着:

  • RAII 类型(管理文件或网络 I/O 句柄、内存、线程锁等资源并在其析构函数中释放这些资源(使其析构函数的清理代码更早而不是更晚地运行,从而优化资源使用持续时间,对它们自己和其他程序的执行具有潜在的流动优势

  • 后面的代码可以出于其他目的重用相同的标识符......如果变量名称在不同的循环中服务于相同的逻辑目的,但恰好在类型上不同,为什么还要继续梦想变量名称?

  • 没有尝试重用变量的风险,在早期不相关的使用后忘记重置其值

  • 阅读代码的程序员在分析代码时使用的范围
  • 后不需要记住它;总而言之,自信地理解代码所需的交叉引用和搜索要少得多。

  • 您可以在各种使用上下文中使用auto以避免此类错误...

 

    float x;
    for (x = my_floats.first(); x < 10; x = my_floats.next())
        ...
    for (x = my_doubles.first(); x < 10; x = my_doubles.next())
        ... oops... getting float precision when double available...
    如果随着代码
  • 的发展,您希望更改变量名称和/或类型以反映其用法,则可以更轻松地以本地化方式执行此操作,而不会使名称通过其他代码产生误导,或者类型变得不合适(可能像上面的float/double示例一样默默地降低结果(; 即使没有具有"重构"支持的花哨IDE, 编译器错误可以帮助您在本地范围内准确地进行更改,而无需执行(更容易出错的(全局搜索和替换...

除了@TonyD的回答:

  • 理想情况下,您应该尽可能靠近使用它们的地点声明变量。

    这使得代码在未到达使用值的执行分支时更快。

    例:

    void f()
    {
        std::string s{ "will be interesting later" ); // some local variable that
                                                      // could have been declared
                                                      // lower in the code
        void g(); // may throw
        use(s);
    }
    

    根据 s 的大小,分配它可能是一项昂贵的操作。但是,如果g抛出,将不需要s,并且分配给它的资源将被浪费。在调用 g 之前分配 s 也意味着 g 将以较少的可用资源运行(考虑到当今计算机的功能,在大多数情况下,这实际上可能无关紧要(。

  • 声明靠近使用它们的位置意味着无需滚动以查看类型定义。您必须向上滚动才能看到的声明是"看不见的"(因此,在脑海中:)(。

  • 编辑/手动重构。考虑想要提取对use不同函数的调用:如果上面的代码没有调用g中间,你可以复制和粘贴。这样,您可以粘贴整个块,然后删除对g的调用,或者复制两次(用于定义s和调用use(。

for 循环范围内声明和初始化变量i的最简单原因是保持代码易于调试和理解,并防止计数器变量在整个程序中不必要地使用内存 execution.ie

在下面的代码中,变量 i 超出 for 循环的范围也会影响 for 循环之外的代码。但是,它仅用作循环的计数器变量。仅当您要保留和使用循环范围之外的循环计数器的值时,才应采用此样式。

int main()
{
    int bigNumber = 10;
    int i;
    for(i = 0; i != bigNumber; ++i){
       cout<<i;
       if(i==2)
       break;
    }
    cout<<"loop terminated at"<<i;
    return 0;
}

就第二种样式而言,它确保变量i的作用和值仅在循环范围之前受到限制。在下面给出的代码中,您将无法在循环范围之外使用计数器变量,从而导致错误。这有助于防止计数器变量不必要的内存使用。

int main()
{
    int bigNumber = 10;
    for(int i = 0; i != bigNumber; ++i){
        cout<<i; 
    }
   cout<<i;
   return 0;
}