Ошибка сегментации в list.begin () - PullRequest
1 голос
/ 14 сентября 2010

У меня есть эта функция-член в моем классе папок:

string _recFullPath() {
 list<Folder*> folders;
 list<Folder*>::iterator it = folders.begin();
 folders.push_front(this);
 it = folders.begin();
 while((*it)->hasParent()) {
  folders.push_front((*it)->parent());
  it = folders.begin();
 }
 folders.push_back(this);
 for(it = folders.begin(); it != folders.end(); ++it) {
  cout << (*it)->getName() << "/";
 }
}

Это компилируется, но когда дело доходит до этого:Я не могу понять, почему.Макет для объекта Папка таков:

class Folder {
  private:
    Folder* _parent;
    string _name;
    string _fullPath;
    string _recStrFullPath;
    bool _hasParent;

  public:
    Folder(string name) {
        this->_name = name;
        this->_hasParent = false;
    }

    Folder(string name, Folder* parent) {
        this->_parent = parent;
        this->_name = name;
        this->_hasParent = true;
    }

    Folder* parent() {
        return this->_parent;
    }

    string getName() {
        return this->_name;
    }

};

И, конечно, вышеупомянутая функция.Может кто-то видит, что я делаю неправильно в приведенном выше коде?

Ответы [ 2 ]

1 голос
/ 14 сентября 2010

Я не знаю, почему ваш цикл while вообще использует итератор. Это было бы чище и проще:

list<Folder*> folders;
Folder* current = this;

while (current->hasParent()) {
    folders.push_front(current);
    current = current.parent();
}

folders.push_front(current);

for(list<Folder*>::const_iterator i = folders.begin(); i != folders.end(); ++i) {
    cout << (*i)->getName() << "/";
}
0 голосов
/ 14 сентября 2010

Обычно не рекомендуется требовать использования указателей в классе без управления хранилищем в этом классе. По крайней мере, вам нужно было бы очень четко указать, как должны работать требования выделения для вызывающей стороны. Вот некоторый код для иллюстрации:

Folder foo(){
    Folder bar("bar");
    Folder baz("baz", &bar);
    return baz;
}

То, что происходит здесь, довольно уродливо, но похоже, что ты сделал то, что должен был. Что происходит при возврате, так это то, что baz копируется в место хранения, куда он должен обратиться для вызывающей стороны, но baz сохраняет указатель на bar. bar (и оригинальная база, у вас есть копия) исчезли, освобождены из стека в конце функции.

Есть несколько способов выбраться из этого беспорядка. Правильный путь - это, вероятно, полностью управлять памятью в самом классе. вот альтернативная версия:

class Folder {
  private:
    Folder* _parent;
    string _name;
    string _fullPath;
    string _recStrFullPath;
    bool _hasParent;

  public:
    Folder(const Folder & src)
        : _name(src._name), _fullPath(src._fullPath)
        , _recStrFullPath(src._recStrFullPath)
        {
        if (src._parent) {
            _parent = new Folder(src._parent);
        }
    }
    ~Folder() {
        delete _parent;
    }

    Folder(string name) {
        this->_name = name;
        this->_hasParent = false;
    }

    Folder(string name, const Folder & parent) {
        this->_parent = new Folder(parent);
        this->_name = name;
        this->_hasParent = true;
    }

    Folder* parent() {
        return this->_parent;
    }

    string getName() {
        return this->_name;
    }

};

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

Чтобы сделать эту работу, были необходимы некоторые изменения в классе. Подпись вызова дочернего формирующего конструктора была изменена, чтобы было ясно, что родительский элемент не затронут. При заполнении _parent копия создается с помощью new.

Чтобы облегчить это, необходимо было добавить еще один конструктор, конструктор копирования, так как нам нужно особенно заботиться об узле _parent.

Наконец, так как мы выполняем эти ресурсы в самом классе, необходимо добавить деструктор для очистки этих ресурсов, когда экземпляр исчезнет.

Теперь вызывающая сторона может выглядеть так:

Folder foo(){
    Folder bar("bar");
    Folder baz("baz", bar);
    return baz;
}

и работайте вежливо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...