我在很长一段时间内第一次写了一些C ++并且记不起来了。我目前正在努力争取范围(以及何时使用指针与输入参数的引用)。具体来说,如果我在堆栈上创建了一些内容,它会保留多长时间?
如果我有一个简单的类:
()
然后我有一个简单的Person Generator方法和main:
class Person {
const std::string name_;
public:
Person(const std::string& name) : name_(name) {}
const std::string& get_name() { return name_; }
};
在我删除之前,该人的名字是否已超出范围?
我知道我可以创建一个新的std :: string并将其传递给Person,但是我还有一个变量需要清理。标准是接受方法签名中的指针或引用吗?
此外,欢迎任何有关此主题的教程的参考。
答案 0 :(得分:2)
这里没有问题。 Person
的构造函数复制堆栈中的值。
答案 1 :(得分:2)
让我们分解一下:
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
的引用被破坏,因为它的范围结束。
name
超出范围。我们返回一个指向生成在堆上的Person
的指针,因此Person
- 其name_
- 不会被破坏。最重要的一步是2.b)
。这里,堆栈上的名称被复制构造到堆中。这是因为name_
不是引用而是值,这使得它与传入的name
“无关”。
Tl; dr这个人的名字不会超出范围,因为只有堆栈上的值才能超出范围。在这种情况下,只有一个指向这个人的指针位于堆栈上,而这个人 - 以及它的名字 - 是在堆上创建的(通过new
)并且不会超出范围。
答案 2 :(得分:1)
你的代码很好。
当您将对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.
答案 3 :(得分:1)
只要堆栈相关,堆栈上分配的东西就会保留在那里,并在弹出堆栈时立即销毁。
C ++倾向于采用两种方法从堆栈中获取数据:在堆上分配,使其持续时间超过当前堆栈范围,并进行复制。
您的name
变量是一个堆栈分配的std::string
,但是这会被复制到您分配的C ++对象,因为您通过引用传递它,而不是指针。
在内部,字符串数据本身可以在堆上分配,这就是这些容器经常工作的方式,但这并不是你真正关心的问题。
简而言之,堆栈对象在其范围的持续时间内持续存在(例如函数或块),除非它们被堆分配或复制到别处。
从风格的角度来看,您真正想要做的是将所有Person
问题都放到课堂上。如果"Bob"
是默认名称,请创建一个构造函数方法,该方法指定:
Person() : name_("Bob") { };
这可以避免get_person()
混淆。
答案 4 :(得分:0)
在你的代码中,人的名字就是bob。
方法签名通常接受引用,但有时您希望通过副本传递。
这可能是方法签名的有用参考。 http://www.cplusplus.com/articles/z6vU7k9E/