C++ 初始化程序不断地在同一内存位置创建新对象
C++ initializer constantly creating new objects at same memory location
我有一个简单的递归类型容器对象"Level"(比如一个目录,它可以包含多个自身),虽然我不确定这是否与这个问题有关。
//Level.h
class Level
{
public:
Level();
vector<Level*> SubLevels;
Level CreateSubLevel();
}
//Level.cpp
Level::Level()
{
SubLevels = vector<Level*>();
}
Level Level::CreateSubLevel()
{
Level NewLevel = Level();
SubLevels.push_back(&NewLevel);
return NewLevel;
}
如果然后在我的主循环中调用
//main.cpp
Level MasterLevel = Level();
MasterLevel.CreateSubLevel();
MasterLevel.CreateSubLevel();
MasterLevel.CreateSubLevel();
我发现向量 MasterLevel.SubLevels 确实包含三个指向 Level 对象的指针。但是,它们都是指向同一个地址的指针!
我不确定为什么会这样。我缺乏内存管理技能 - 但我怀疑这是因为每次调用 CreateSubLevel() 时都会创建一个新对象,但当 CreateSubLevel() 退出时它会被删除?我以为 ARC 会跟踪指向它的指针仍然存在的事实,但也许我错了?或者这完全是另一个问题?
我怎样才能最好地解决这个问题?
谢谢!
SubLevels
持有三个指向临时对象的指针。编译器选择每次都为临时对象重用相同的内存并不奇怪——为什么不呢?
如果您想实际正确存储三个不同的 Level
,您要么必须按值存储它们:
vector<Level> SubLevels;
SubLevels.push_back(Level());
或者实际分配Level
s:
vector<Level*> SubLevels;
SubLevels.push_back(new Level); // don't forget to delete!
你每次得出相同值的原因是因为你使用的是临时变量(在堆栈上)的地址。每次调用函数 CreateSubLevel()
时,都会重复使用堆栈,因此每次调用时对象都存储在相同的位置。
您可以使用 operator new()
:
在堆上分配对象
vector<Level*> SubLevels;
SubLevels.push_back(new Level);
然后你可以在析构函数中delete
它们:
Level::~Level()
{
vector<Level*>::iterator i;
for (i = SubLevels.begin(); i != SubLevels.end(); ++i)
delete *i;
}
您接连打了三个 MasterLevel.CreateSubLevel();
电话。每次调用都会创建一个大小相同的堆栈帧。因此,局部变量的地址是相同的。您将局部变量的地址存储在 SubLevels
.
中
如果你使用存储在SubLevels
中的地址,你会运行进入未定义的行为。您需要从堆中分配内存。
当你这样做的时候,保留一个智能指针列表,std::unique_ptr
或 std::shared_ptr
而不是存储原始指针。
使用
vector<std::shared_ptr<Level>> SubLevels;
并将其用作:
void Level::CreateSubLevel()
{
SubLevels.push_back(std::make_shared<Level>());
}
我有一个简单的递归类型容器对象"Level"(比如一个目录,它可以包含多个自身),虽然我不确定这是否与这个问题有关。
//Level.h
class Level
{
public:
Level();
vector<Level*> SubLevels;
Level CreateSubLevel();
}
//Level.cpp
Level::Level()
{
SubLevels = vector<Level*>();
}
Level Level::CreateSubLevel()
{
Level NewLevel = Level();
SubLevels.push_back(&NewLevel);
return NewLevel;
}
如果然后在我的主循环中调用
//main.cpp
Level MasterLevel = Level();
MasterLevel.CreateSubLevel();
MasterLevel.CreateSubLevel();
MasterLevel.CreateSubLevel();
我发现向量 MasterLevel.SubLevels 确实包含三个指向 Level 对象的指针。但是,它们都是指向同一个地址的指针!
我不确定为什么会这样。我缺乏内存管理技能 - 但我怀疑这是因为每次调用 CreateSubLevel() 时都会创建一个新对象,但当 CreateSubLevel() 退出时它会被删除?我以为 ARC 会跟踪指向它的指针仍然存在的事实,但也许我错了?或者这完全是另一个问题?
我怎样才能最好地解决这个问题?
谢谢!
SubLevels
持有三个指向临时对象的指针。编译器选择每次都为临时对象重用相同的内存并不奇怪——为什么不呢?
如果您想实际正确存储三个不同的 Level
,您要么必须按值存储它们:
vector<Level> SubLevels;
SubLevels.push_back(Level());
或者实际分配Level
s:
vector<Level*> SubLevels;
SubLevels.push_back(new Level); // don't forget to delete!
你每次得出相同值的原因是因为你使用的是临时变量(在堆栈上)的地址。每次调用函数 CreateSubLevel()
时,都会重复使用堆栈,因此每次调用时对象都存储在相同的位置。
您可以使用 operator new()
:
vector<Level*> SubLevels;
SubLevels.push_back(new Level);
然后你可以在析构函数中delete
它们:
Level::~Level()
{
vector<Level*>::iterator i;
for (i = SubLevels.begin(); i != SubLevels.end(); ++i)
delete *i;
}
您接连打了三个 MasterLevel.CreateSubLevel();
电话。每次调用都会创建一个大小相同的堆栈帧。因此,局部变量的地址是相同的。您将局部变量的地址存储在 SubLevels
.
如果你使用存储在SubLevels
中的地址,你会运行进入未定义的行为。您需要从堆中分配内存。
当你这样做的时候,保留一个智能指针列表,std::unique_ptr
或 std::shared_ptr
而不是存储原始指针。
使用
vector<std::shared_ptr<Level>> SubLevels;
并将其用作:
void Level::CreateSubLevel()
{
SubLevels.push_back(std::make_shared<Level>());
}