引用的C++变量作用域

C++ variable scope for references

本文关键字:作用域 变量 C++ 引用      更新时间:2023-10-16

我很长时间以来第一次写C++,记不清了。我目前最纠结的是作用域(以及何时使用指针与引用作为输入参数(。具体来说,如果我在堆栈上创建了一些东西,它会在那里停留多久?

如果我有一个简单的类,比如:

class Person {
    const std::string name_;
public:
    Person(const std::string& name) : name_(name) {}
    const std::string& get_name() { return name_; }
};

然后我有一个简单的人员生成器方法和主要:

Person* get_person() {
    std::string name = "Bob";
    return new Person(name);
}
int main (int argc, char **argv) {
    Person* person = get_person();
    // Is person's name Bob here? Or did Bob go out of scope?
    delete person;
}

在我删除这个人之前,这个人的名字已经超出范围了吗?

我知道我可以创建一个新的std::字符串并将其传递给Person,但之后我还有一个变量要清理。在方法签名中接受指针或引用的标准是什么?

此外,欢迎参考有关此主题的教程。

让我们来分解一下:

Person* get_person() {
    std::string name = "Bob"; // 1)
    return new Person(name); // 2)
} // 3)
  1. 字符串名称已创建

    这里在堆栈上创建字符串name

  2. 在堆上创建了一个新人

    我们必须查看构造函数,看看发生了什么

class Person {
    const std::string name_; 
public:
    Person(const std::string& name) : // 2.a)
        name_(name) // 2.b)
    {} // 2.c)
}

a( name是通过引用传递的。对name的引用存在于当前帧中,而name存在于前一帧中的堆栈上。

b( name复制构造的到CCD_ 6中。因为人是在堆上创建的,所以name_也生活在堆上。

c( 对name的引用被销毁,因为它的作用域结束了。

  1. 块结束,因此name将超出范围。我们返回一个指向堆上的Person的指针,因此Person及其name_不会被销毁

最重要的步骤是2.b)。在这里,堆栈上的名称被复制构造到中。这是因为name_不是一个引用,而是一个值,这使得它与传入的name"独立"。


Tl;dr人名不会超出作用域,因为只有堆栈上的值才能超出作用域。在这种情况下,只有指向人员的指针位于堆栈上,而人员及其名称是在堆上创建的(通过new(,不会超出范围。

您在这里没有任何问题。Person的构造函数复制堆栈上的值。

只要堆栈相关,堆栈上分配的东西就会一直存在,并在堆栈弹出时立即销毁。

C++倾向于使用两种方法从堆栈中获取数据:在堆上进行分配,使其比当前堆栈范围持续更长时间;以及复制。

您的name变量是一个堆栈分配的std::string,但它被复制到您分配的C++对象,因为您通过引用而不是指针传递它。

在内部,字符串数据本身可能会在堆上分配,这就是这些容器通常的工作方式,但这并不是您真正关心的问题。

简而言之,堆栈对象在其作用域(例如函数或块(的持续时间内保持不变,除非它们被堆分配或复制到其他地方。

从风格的角度来看,您真正想做的是将所有Person关注点合并到类中。如果"Bob"是默认名称,则创建一个构造函数方法来分配:

Person() : name_("Bob") { };

这避免了get_person()的混淆。

您的代码很好。

当您将对name的引用传递给构造函数时,构造函数将从中生成一个新字符串,即name_将是name的副本并放置在堆中。

从get_person返回后,变量名超出了作用域,但已经创建了一个副本。

所以——没问题。

发件人http://www.cplusplus.com/reference/string/string/string/

copy (2): string (const string& str);
(2) copy constructor Constructs a copy of str.

在代码中,Person的名字应该是bob。

方法签名通常接受引用,但有时需要通过副本传递。

这可能是方法签名的有用参考。http://www.cplusplus.com/articles/z6vU7k9E/