我想知道类成员(属性)的生命周期是什么。
当前我有这个课程:
class Snake {
private:
std::vector<Position> positions = std::vector<Position>();
public:
void addNode(Position * position);
};
并且不确定addNode函数是否必须接收指针或对象? 我的猜测是,如果addNode接收到Position位置作为参数,则对象将超出其创建范围,例如
... code here ...
{
Position p = Position(..);
snake.addNode(p);
}
// p should die over here so it could cause a null pointer on the program
另一方面,如果addNode收到一个指针,则p除非我删除它,否则它不会死亡(因此它不会导致任何空指针),也许你们可以帮我澄清一下有关我现在拥有的指针的巨大困惑,
谢谢。
答案 0 :(得分:2)
对象不必是指针,但是指针是对象。指针只是一个存储数字的对象,该数字是某个对象的内存地址。当指针超出范围时,它不会不删除其指向的对象(因此会导致内存泄漏)。
如果您希望自己的代码性能最高并且更正,则应该:
const
引用代替指针。如下所示,这将是代码:
void addNode(const Position& position)
{
positions.push_back(position);
}
void addNode(Position&& position)
{
positions.push_back(std::move(position));
}
它可以避免制作冗余副本并使用const Position
作为参数。
这种方法比其他answears(void addNode(Position position)
)中建议的方法要快,因为它避免了将参数复制到函数中。
另一种优化方法是,当您知道该位置将超出范围时,将位置移至该函数:
{
Position p = Position(x, y);
snake.addNode(std::move(p)); //mind the std::move
} //p will go out of scope here anyway, so it can safely be moved
答案 1 :(得分:1)
我们假设addNode
已实现
addNode(Position p){
positions.push_back(p);
}
输入变量是您传入的变量的副本。在向量上调用push_back后,向量内将创建另一个副本,当向量被销毁时,该副本也将被销毁。此后p将被销毁,但这没有影响,因为vector包含一个副本。通常,如果编译器很聪明,则可以避免某些复制,并且可以通过使用例如std :: move来改进代码,但我不想在答案中增加太多复杂性。>
您对“空指针”的评论有点不准确:如果您有一个指针向量,则可以在向量中插入一个指向p的指针。如果p超出范围,指针将悬空,从而使程序的行为不确定。
答案 2 :(得分:0)
不要使用指针,这明显是怎么回事?
public:
void addNode(Position position);
关键是尽管函数退出后position
参数就会消失,但它的值是向量中的 COPIED ,并且副本仍然存在于向量中,即使原始的已经死了。
这里真的不需要指针。
答案 3 :(得分:0)
类成员的生命周期与实例相关。它的生命始于构造函数的初始化程序列表,并终止于析构函数调用的末尾。
您似乎给人的印象是,类是参考值-使用C#术语-不是。所有C ++对象都是值类型:
{Position p;...}
是类型Position
的对象。它的构造函数在块的开头创建对象,并在结尾处调用其析构函数,这会破坏其内容和对象本身。 {Position* ptr{&p};...}
是类型Position*
的对象。它是“构造函数”来初始化指针。它的析构函数是no-op,但是如果存在,那么它将破坏它的value = address = number而不是它所指向的对象。指针是指向另一个对象的地址,并且在该块的末尾,无论指针的内容如何,该指针都会被破坏。就像{int i = 0;}会破坏i
,而不是0
。
{Position& ptr{p};...}
与指针的规则相同。引用被销毁,而不是被引用的对象。
核心思想是指针只是另一种普通的值类型:
Position p;
//Introduces a new name for a type
using Position_p = Position*;
Position_p p1 = &p;
Position_p p2 = p1;
p2++; // Change p2
//p1 is still the same.
int i1 = 5;
int i2 = i1;
i2++; // Change i2
//i1 is still the same.
它们看起来相同,甚至副本也表现出应有的状态。就像i2
获取i1
的内容一样,p2
获取p1
的内容。对于int
,内容是数字;对于Position_p
,内容是地址。如果您了解这个概念,那么指针应该变得非常直观。
所以我的猜测是您想拥有std::vector<Position>
和addNode(Position p)
。但这会产生不必要的副本,因此addnode(const Position& p)
更好。在内部可以执行push_back
,并将值复制到向量中。如果需要,可以使用move语义摆脱最后的副本。