указатели — инициализатор C ++, постоянно создающий новые объекты в одной и той же области памяти

У меня есть простой контейнерный объект рекурсивного типа «Уровень» (например, каталог, который может содержать кратные числа самого себя), хотя я не уверен, что это связано с этой проблемой.

//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 будет отслеживать тот факт, что указатель на него все еще существует, но, возможно, я ошибаюсь? Или это совсем другая проблема?

Как я могу лучше всего решить эту проблему?

Спасибо!

0

Решение

SubLevels держит на три указателя на временные. Неудивительно, что компилятор решил каждый раз повторно использовать одну и ту же память — почему бы и нет?

Если вы хотите на самом деле хранить три разных LevelЭто правильно, вам придется хранить их по значению:

vector<Level> SubLevels;
SubLevels.push_back(Level());

Или на самом деле выделить Levels:

vector<Level*> SubLevels;
SubLevels.push_back(new Level); // don't forget to delete!
2

Другие решения

Причина, по которой вы каждый раз получаете одно и то же значение, заключается в том, что вы используете адрес временной переменной (в стеке). Каждый раз, когда функция 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;
}
1

У вас есть три звонка 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>());
}
1
По вопросам рекламы [email protected]