超出作用域在c++对象中意味着什么

What does going out of scope means in c++ objects?

本文关键字:意味着 什么 对象 c++ 作用域      更新时间:2023-10-16

我知道对象超出范围的一种情况。例如,假设我们已经从main()调用了一个函数foo()。

int foo()
{
   someobject obj;
   //do something with this object
   return -1;
}

现在我知道,由于这个对象是在堆栈上声明的,当foo()结束时,这个对象将从堆栈中删除。有人能解释一下对象超出范围的其他情况吗还有一件事,为什么在堆栈上声明这个对象

void foo()
{
    int obj1;
    {
        int obj2;
        // obj1, obj2 can be used here
        {
            int obj1;
            //in this scope obj1 is not the first obj1, it's the one declared in previous line
        }
        // obj1 in this will refer the first obj1
    }
}

关于第二个问题,默认情况下,当您在函数内部创建某个对象时,它将在堆栈上。它是首选,因为我们不必关心分配的内存。它将自动从堆栈中删除。

我们可以使用new在堆上创建内存,但在这种情况下,我们必须确保一旦完成,我们已经删除了分配的内存,或者确保转移了对象的所有权,以便删除它。

检查以下情况。

void foo1()
{
    int* i = new int(23);
    // use i here ...
    // .....
    delete i; // once done delete the memory, it exception is thrown here i will not be deleted so make sure to use smart pointer(RAII)
}
void foo2()
{
    unique_ptr<int> iPtr(new int(23));
    // use iPTr here ...
    // .....
    // no need to delete allocated memory, unique_ptr will handle that
}

为了避免不必要的内存管理,我们在堆栈上创建对象。此外,在嵌入式域中,不建议使用动态内存分配,因为它不安全。

这是在堆栈上声明的对象,因为一旦调用了这个返回的整数函数,它就实现了它的目的。我要说的是,你最初使用这个对象的方式有点奇怪。为什么不直接将对对象的引用作为函数的输入参数呢。

int foo(object) {

}

至于对象可能超出范围的其他情况,则完全取决于创建对象的线程或位置。

C++中有两个重要的概念:

  • 范围
  • 存储持续时间

两者相互作用,但又截然不同。(还有第三个概念,对象生存期,对于"正常"程序,它几乎与对象的存储持续时间相同;现在我们忽略它。)

让我们检查范围

Scope表示"名称可见且有效"。中心概念是名称标准在3.3.1 中说明

通常,每个特定的名称仅在某些情况下有效程序文本中不连续的部分称为其作用域[我强调。]

i这样的名称可能超出作用域。这意味着人们不能再使用它来指代特定的对象。您给出的示例是正确的:当一个封闭块(如函数体)被留下时。另一个例子是当两个实体具有相同的名称时,如全局i和局部循环变量i。全局i作用域不包括循环(这是不同的i)。但是全局i对象的存储持续时间(以及因此的生存期)当然包括循环——它仍然"在那里"(例如,可以使用指针来访问它)。

相比之下,存储持续时间不是一个正式的语法问题,而是一个实际操作的运行时问题。核心概念是存储:恰当命名的存储持续时间描述了保存对象的存储有效期。(请参阅我们如何不关心名称。)标准在3.7中规定:

存储持续时间是定义存储包含的最小潜在寿命对象。存储持续时间由构造,用于创建对象,并且是以下对象之一:

  • 静态存储持续时间
  • 线程存储持续时间
  • 自动存储持续时间
  • 动态存储持续时间

[我强调。]

最简单的"创建对象的构造"就是简单地在函数中声明一个局部变量。这样创建的存储具有恰当命名的"自动"存储持续时间——实现在执行定义时创建对象(最新?),并在保留名称的作用域时为您销毁对象。对于自动变量,名称范围和存储持续时间之间的联系很强。

但请注意,还可以在块中声明一个外部变量或函数,从而为外部实体提供一个具有本地作用域的名称:

$ cat local-external.cpp && g++  -Wall -o local-external local-external.cpp && ./local-external
int main()
{
        {
                extern int i;
        }
        i=1;
}
local-external.cpp: In function ‘int main()’:
local-external.cpp:4:14: warning: unused variable ‘i’ [-Wunused-variable]
   extern int i;
              ^
local-external.cpp:6:2: error: ‘i’ was not declared in this scope
  i=1;
  ^

i作用域与局部变量(从其声明到封闭块的末尾)相同,但其存储持续时间(如果存在对象,例如在不同的文件中定义的对象)将是静态的,因为它是一个外部变量,与程序一样长。如果将赋值移到内部块中以便编译代码,则链接器会抱怨找不到外部对象i(应该放在某个地方的存储)。

当然,很少有人做这样的事;这只是一个示范。(声明本地函数通常是无意中完成的。)