代码之家  ›  专栏  ›  技术社区  ›  Kirill V. Lyadvinsky

局部变量范围问题

  •  8
  • Kirill V. Lyadvinsky  · 技术社区  · 16 年前

    我认为根据C++标准3.3.2“ 在块中声明的名称是该块的本地名称。它的潜在作用域从声明点开始,到声明区域的末尾结束。 "

    #include <iostream>
    using namespace std;
    
    class MyClass
    {
    public:
      MyClass( int ) { cout << "x" << endl; };
      ~MyClass() { cout << "x" << endl; };
    };
    
    int main(int argc,char* argv[])
    {
      MyClass  (12345);
    // changing it to the following will change the behavior
    //MyClass m(12345);
      cout << "Y" << endl;
    
      return 0;
    }
    

    MyClass(12345); 是表达式(和范围)。这是有道理的。因此,我预计以下代码将始终打印“xYx”:

    MyClass (12345), cout << "Y" << endl;
    

    // this much strings with explicit scope
    {
      boost::scoped_lock lock(my_mutex);
      int x = some_func(); // should be protected in multi-threaded program
    } 
    // mutex released here
    
    //    
    
    // I can replace with the following one string:
    int x = boost::scoped_lock (my_mutex), some_func(); // still multi-thread safe
    // mutex released here
    
    4 回复  |  直到 16 年前
        1
  •  16
  •   JesperE    16 年前

    在您的

    MyClass(12345);
    

    是一个只有生命的临时对象 在那个表达中 ;

    MyClass m(12345);
    

        2
  •  8
  •   Philippe Leybaert    16 年前

    您实际上是在创建一个对象,而没有将其保留在范围内,因此它在创建后立即被销毁。因此,你正在经历的行为。

        3
  •  5
  •   Community Mohan Dere    5 年前

    回答你的其他问题。以下是逗号运算符的调用。它创造了一个 MyClass 临时的,包括调用它的构造函数。然后,它计算第二个表达式 cout << "Y" << endl 它将打印出Y。然后,在完整表达式的末尾,它将销毁临时变量,并调用其析构函数。所以你的期望是对的。

    MyClass (12345), cout << "Y" << endl;
    

    为了使以下内容生效,您应该添加括号,因为逗号在声明中具有预定义的含义。它将开始声明一个函数 some_func 返回a int 不接受任何参数,并将分配 scoped_lock 反对 x

    int x = (boost::scoped_lock (my_mutex), some_func()); // still multi-thread safe
    

    应当注意,以下两行是等价的。第一个是 使用以下命令创建临时未命名对象 my_mutex

    boost::scoped_lock(my_mutex);
    boost::scoped_lock my_mutex;
    

    我见过范围和寿命这两个术语的误用。

    • Scope 在这里,你可以引用一个名字,而不用限定它的名字。名称有作用域,对象继承用于定义它们的名称的作用域(因此有时标准称之为“本地对象”)。临时对象没有作用域,因为它没有名称。同样,一个由以下方式创建的对象 new 没有范围。作用域是一个编译时属性。该术语在标准中经常被误用,请参见 this defect report ,所以要找到真正的含义是相当令人困惑的。

    • Lifetime 是一个运行时属性。这意味着对象已设置并准备好使用。对于类类型对象,生存期从构造函数结束执行时开始,到析构函数开始执行时结束。生命周期经常与范围相混淆,尽管这两件事完全不同。

      临时工的寿命是精确定义的。它们中的大多数在计算完它们所包含的完整表达式(如上面的逗号运算符或赋值表达式)后结束生命周期。时态可以绑定到const引用,这将延长它们的生命周期。在异常中抛出的对象也是临时对象,当不再有处理程序时,它们的生命周期就结束了。

        4
  •  4
  •   P Shved    15 年前

    你正确地引用了标准。让我强调:

    A. 名字 在一个块中,它是该块的局部。它的潜在作用域从声明点开始,到声明区域的末尾结束。

    你没有申报任何 名字 事实上。你的 线

    MyClass (12345);
    

    甚至不包含声明 !它包含一个表达式,该表达式创建MyClass的实例,计算表达式(但是,在这种特殊情况下,无需计算任何内容),并将其结果转换为 void ,并销毁在那里创建的对象。

    一件不那么令人困惑的事情听起来像

    call_a_function(MyClass(12345));
    

    你看过很多次,知道它是怎么工作的,不是吗?

    推荐文章