У меня есть простой контейнерный объект рекурсивного типа «Уровень» (например, каталог, который может содержать кратные числа самого себя), хотя я не уверен, что это связано с этой проблемой.
//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 содержит три указателя на объекты уровня. Тем не менее, они все указатели на один и тот же адрес!
Я не уверен, почему это происходит. У меня нет навыков управления памятью — но я подозреваю, что это потому, что каждый раз, когда вызывается 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>());
}