Утечки памяти вызваны циклическими ссылками? - PullRequest
0 голосов
/ 07 января 2019

Я создаю двусвязный список в C ++. При добавлении в начало списка я получаю следующую утечка памяти :

Detected memory leaks!
Dumping objects ->
{193} normal block at 0x000001F7A1EC01B0, 16 bytes long.
 Data: < 0              > A0 30 EB A1 F7 01 00 00 00 00 00 00 00 00 00 00 
{192} normal block at 0x000001F7A1EB3090, 96 bytes long.
 Data: < [J             > D0 5B 4A AE F7 7F 00 00 02 00 00 00 01 00 00 00 
{149} normal block at 0x000001F7A1EBF9E0, 16 bytes long.
 Data: <   #            > D8 F7 15 23 E4 00 00 00 00 00 00 00 00 00 00 00 
Object dump complete.

Вот мой код:

struct Node {
    bool exists = false;
    int element;
    shared_ptr<node> prevNode = nullptr;
    shared_ptr<node> nextNode = nullptr;
};

class DLL {
public:
    shared_ptr<Node> frontNode = make_shared<Node>();
    shared_ptr<Node> backNode = make_shared<Node>();
    void frontAdd(int x);
}

void DLL::frontAdd(int x) {
    shared_ptr<Node> tempNode = make_shared<Node>();
    tempNode->exists = true;
    tempNode->element = x;
    tempNode->prevNode = nullptr;

    if (frontNode->exists) {
        tempNode->nextNode = frontNode;
        frontNode->prevNode = tempNode;
    }
    else {
        backNode = tempNode;
    }

    frontNode = tempNode;
};

Я пытался использовать уникальные указатели и слабые указатели, но я незнаком со слабыми указателями, и как новичок мне было очень трудно интегрировать их в этот проект. Я попытался удалить make_shared на frontNode и tempNode и вместо этого создать их без make_shared, но в обоих случаях это возвращает нарушение прав записи, говорящее «вернул nullptr». В autos tempNode пуст, так что это имеет смысл.

Поскольку shared_ptr выходит из области видимости, я ожидал, что все владение будет потеряно, а утечки памяти не будет, но я предполагаю, что из-за «make_shared» он был добавлен в кучу и поэтому не может быть удален из памяти так легко?

Ответы [ 2 ]

0 голосов
/ 07 января 2019

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

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

0 голосов
/ 07 января 2019

Вполне вероятно, что ваша круговая ссылка является причиной. shared_ptr не такой умный, он просто подсчитывает количество ссылок, а обратный указатель сохраняет счетчик ненулевым.

Вам нужно использовать либо необработанные указатели, либо weak_ptr <> для всего, что можно считать указателем «назад», либо из подчиненного дочернего объекта, либо там, где у вас есть двусторонний список.

weak_ptr<> имеет эксплуатационные расходы, но имеет то преимущество, что дочерний объект может действовать безопасно с минимальными усилиями по кодированию.

...