繁体   English   中英

C ++变量范围供参考

[英]C++ variable scope for references

我很长时间以来第一次写一些C ++,记不清了。 我目前在范围方面(以及何时使用指针与引用作为输入参数的参考)最费劲。 具体来说,如果我在堆栈上创建某些内容,那么该内容将在其中保留多长时间?

如果我有一个简单的课程,例如:

class Person {
    const std::string name_;

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

然后,我有一个简单的Person Generator方法和main:

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 :: string并将其传递给Person,但是我还有一个要清除的变量。 在方法签名中接受指针或引用的标准吗?

另外,也欢迎参考该主题的教程。

您在这里没有问题。 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复制name_ 因为此人是在堆上创建的,所以name_在堆上。

c)对name的引用被破坏了,因为它的范围结束了。

  1. 块结束,因此name不在范围内。 我们返回一个指向name_在堆上的Person的指针,因此Person (带有name_ )不会被销毁。

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


Tl; dr人的名字不会超出范围,因为只有堆栈上的值才可以超出范围。 在这种情况下,只有指向人的指针位于堆栈上,而人及其名称将在堆上创建(通过new ),并且不会超出范围。

您的代码很好。

当您将对名称的引用传递给构造函数时,构造函数将从中创建一个新字符串,即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.

只要堆栈是相关的,分配在堆栈上的内容将一直保留在那里,并在弹出堆栈时立即销毁。

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

您的name变量是堆栈分配的std::string但是由于您通过引用而不是指针传递它,因此将其复制到分配的C ++对象中。

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

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

从风格上来看,您真正想要做的就是将所有有关Person问题折叠到类中。 如果"Bob"是默认名称,请创建一个构造器方法来分配该名称:

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

这避免了get_person()混乱。

在您的代码中,“人”的名字会在那里出现。

方法签名通常接受引用,但是有时您希望通过副本传递。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM