局部变量范围问题

Kir*_*sky 8 c++ scope raii

为什么以下代码打印"xxY"?局部变量不应该存在于整个函数的范围内吗?我可以使用这种行为,或者在将来的C++标准中会改变这种行为吗?

我认为根据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;
}
Run Code Online (Sandbox Code Playgroud)

基于响应,我可以假设这MyClass(12345);是表达式(和范围).这是有道理的.所以我希望以下代码将始终打印"xYx":

MyClass (12345), cout << "Y" << endl;
Run Code Online (Sandbox Code Playgroud)

并且允许进行这样的替换:

// 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
Run Code Online (Sandbox Code Playgroud)

Jes*_*erE 16

在你的对象中创建的对象

MyClass(12345);
Run Code Online (Sandbox Code Playgroud)

是一个临时的对象,它只存在于那个表达中 ;

MyClass m(12345);
Run Code Online (Sandbox Code Playgroud)

是一个对整个街区都有活力的对象.


Phi*_*ert 8

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

您无法访问创建的对象,为什么编译器会保留它?


Joh*_*itb 5

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

MyClass (12345), cout << "Y" << endl;
Run Code Online (Sandbox Code Playgroud)

要使以下工作,您应该添加括号,因为逗号在声明中具有预定义含义.它将开始声明一个函数some_func返回int并且不带参数,并将scoped_lock对象分配给x.使用括号,您可以说整个事件只是一个逗号运算符表达式.

int x = (boost::scoped_lock (my_mutex), some_func()); // still multi-thread safe
Run Code Online (Sandbox Code Playgroud)

应该注意,以下两行是等效的.第一个原因不能创建使用临时无名对象my_mutex的构造函数的参数,而是围绕着名的括号是多余的.不要让语法混淆你.

boost::scoped_lock(my_mutex);
boost::scoped_lock my_mutex;
Run Code Online (Sandbox Code Playgroud)

我看到滥用术语范围和生命周期.

  • Scope您可以在不使用其名称的情况下引用名称.名称具有范围,对象继承用于定义它们的名称的范围(因此有时标准称为"本地对象").临时对象没有范围,因为它没有名称.同样,创建的对象new没有范围.Scope是一个编译时属性.这个术语在标准中经常被滥用,请参阅此缺陷报告,因此找到真正的含义会让人感到困惑.

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

    临时工作的生命周期是精确定义的.它们中的大多数在评估它们包含的完整表达式后终止生命周期(例如,上面的逗号运算符或赋值表达式).临时工具可以绑定到const引用,这将延长它们的寿命.在异常中抛出的对象也是临时对象,并且当它们不再存在处理程序时它们的生命周期结束.