Безопасно ли удалять родительский элемент вектора указателей, когда эти указатели были опубликованы? - PullRequest
0 голосов
/ 15 марта 2020

В одном из моих приложений возникают проблемы с утечкой памяти, которые я пытаюсь устранить. Одна из моих предполагаемых проблемных точек - это то, где я разбираю строки из файла в команды, используя BNF C:

void LineStreamScriptProvider::populateQueue()
{
    if(shouldPopulate())
    {
        TasScript::ShowAbsyn shower;
        std::string line;
        while(queueSize() < 30 && !stream.eof())
        {
            std::getline(stream, line);
            const char* lineCStr = line.c_str();
            TasScript::Program* lineCmds = TasScript::pProgram(lineCStr);
            TasScript::P* asLeaf = static_cast<TasScript::P*>(lineCmds);
            TasScript::ListCommand* cList = asLeaf->listcommand_;
            for_each(cList->begin(), cList->end(), [this, shower](TasScript::Command* cmd) {
                // log_to_sd_out("Parsed command %s\n", shower->show(cmd));
                std::shared_ptr<TasScript::Command> cmdShared(cmd);
                pushToQueue(cmdShared);
            });
        }
        if(stream.eof())
        {
            afterEOF();
        }
    }
}

Для справки:

class P : public Program
{
public:
  ListCommand *listcommand_;
// ...
class ListCommand : public Visitable, public std::vector<Command*>
{
// ...

BNF C конструирует их с new и затем возвращает указатели. Безопасно ли delete lineCmds без удаления значения cmdShared?

1 Ответ

1 голос
/ 17 марта 2020

Извините, я не знал о BNF C и о том, что он создает необработанные указатели для вас.

Безопасно ли удалять lineCmds без удаления значения, хранящегося в cmdShared?

Если вы создаете общий указатель из необработанного указателя, общий указатель становится владельцем этого ресурса. Общий указатель будет поддерживать счетчик ссылок для этого ресурса до тех пор, пока он не упадет до нуля, т. Е. Когда все общие указатели для этого ресурса go выйдут из области видимости, в этот момент он попытается уничтожить ресурс.

Здесь Вы создаете общий указатель и передаете его в очередь:

std::shared_ptr<TasScript::Command> cmdShared(cmd);
pushToQueue(cmdShared);

Общий указатель позаботится об управлении памятью. Поэтому нет необходимости явно вызывать delete для вектора команд. Как только все общие указатели типа std::shared_ptr<TasScript::Command> уничтожены, ресурс также уничтожается.

Так что нет, в этом случае небезопасно удалять вектор указателей.


Другой Более простое решение - взять копию TasScript::Command:

TasScript::Command cmdCopy(*cmd);

, затем изменить pushToQueue() для принятия на const TasScript::Command&, а не на общий указатель. Тогда вам не нужно беспокоиться об уничтожении указателя, так как у вас есть копия значения.

Похоже, что в то время, когда вы oop теряете память. Не нужно ли удалять lineCmds и cList?

...