我很长时间以来第一次写一些 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* get_person() {
std::string name = "Bob"; // 1)
return new Person(name); // 2)
} // 3)
字符串名称创建
此处在堆栈上创建了字符串
name
。在堆上创建一个新的人
我们必须查看构造函数以了解发生了什么
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
的引用被销毁,因为它的作用域结束了。
- block 结束,因此
name
超出范围。我们返回一个指向堆上的Person
的指针,因此Person
- 及其name_
- 不会被销毁。
最重要的一步是2.b)
。在这里,堆栈 中的名称被复制构造到堆 中。这是因为 name_
不是引用而是一个值,这使得它“独立”于传入的 name
。
Tl;dr 这个人的名字不会超出范围,因为只有堆栈上的值才能超出范围。在这种情况下,只有一个指向人的指针位于堆栈中,而人及其名称是在堆上创建的(通过 new
)并且不会超出范围。
关于引用的 C++ 变量范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31345509/