Ссылка на общий указатель повреждена - PullRequest
0 голосов
/ 17 января 2019

Ссылка на общий указатель повреждается, даже если shared_ptr все еще принадлежит.

У меня есть что-то вроде следующего фрагмента кода в приложении, и я продолжаю получать свисающие ссылки на указатели или некоторые другие искажения при попытке использовать ссылки на shared_ptr внутри объекта класса. Приведенный ниже тест также показывает ту же проблему на RHEL7 с использованием gcc 5.4.0. Так же бывает и с clang 4.0.1. Я убедился, что shared_ptr никогда не разрушает указанный объект до тех пор, пока система не выйдет.

При хранении shared_ptr в A все работает просто отлично.

#include <cassert>
#include <iostream>
#include <memory>
#include <vector>

using namespace std;

class Int
{
  public:
    Int() : Int(0) { }
    Int(int v) : _val(v) { }
    int val() const { return _val; }
    ~Int() { }

  private:
    int _val;
};

typedef shared_ptr<Int> IntPtr;

class A
{
  public:
    IntPtr &intPtr;
    A() = delete;
    A(IntPtr &int_ptr) : intPtr(int_ptr)
    {
        cout << "A()" << endl;
        cout << intPtr.use_count() << endl;
        cout << intPtr->val() << endl;
    }
};

class B
{
  public:
    B(A *a) : _a(a) { }
    B() = delete;
    A *_a;
};

vector<IntPtr> intPtrs;

A* makeNew()
{
    IntPtr int_ptr = make_shared<Int>(44883);
    intPtrs.push_back(int_ptr);
    cout << "makeNew()" << endl;
    cout << intPtrs.back().use_count() << endl;
    cout << intPtrs.back()->val() << endl;
    A *a = new A(int_ptr);

    return a;
}

void checkB(B *b)
{
    A *a = b->_a;
    assert(a);
    cout << "checkB()" << endl;
    cout << a->intPtr.use_count() << endl;
    cout << a->intPtr->val() << endl;
}

int main(int argc, char *argv[])
{
    B *b = new B(makeNew());
    checkB(b);
    cout << "main()" << endl;
    A *a = b->_a;
    cout << a->intPtr.use_count() << endl;
    cout << a->intPtr->val() << endl;

    cout << "intPtrs size: " << intPtrs.size() << endl;

    for (const auto &int_ptr : intPtrs) {
        cout << int_ptr.use_count() << endl;
        cout << int_ptr->val() << endl;
    }

    return 0;
}

makeNew () 2 44883 А () 2 44883 checkB () -324888 -610139856 главный() -610139968 -1066293104 размер intPtrs: 1 1 44883

Выше сгенерированный вывод, как можно увидеть в checkB () или при проверке вновь созданного объекта в main () я получаю мусор.

Поскольку вектор является владельцем IntPtr и имеет время жизни, которое длится до завершения программы, я ожидаю, что ссылка в A будет в порядке.

1 Ответ

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

makeNew возвращает указатель на A, который содержит ссылку на IntPtr; но это IntPtr уже уничтожено, это была локальная переменная в makeNew. Таким образом, ссылка становится недействительной.

Я бы предположил, что shared_ptr подсчет ссылок работает, когда вы присваиваете ptr другой переменной, но не когда сохраняете ссылку на нее.

...