-2
#include <iostream>

using namespace std;

template <typename T>

class SmartPointer {
    private:
        T* p;
        int count = 0;
    public:

        SmartPointer(T* pb) { // Конструктор
            p = pb;
            count++;
            cout << "Constructor - " << (&p) << count << endl;
        }

        SmartPointer(const SmartPointer& ConPtr) {
            p = ConPtr.p;
            count = ConPtr.count;
            count++;
            cout << "Constructor Copy - " << (&p) << count << endl;
        }

        SmartPointer& operator = (const SmartPointer& ConOper) {
            if (this != &ConOper) {
                Release();
                p = ConOper.p;
                count = ConOper.count;
                count++;
                cout << "Reload operator - " << (&p) << count << endl;
            }
            return *this; 
        }

        ~SmartPointer() { // Деструктор
            cout << "Destructor" << (*p) << endl;
            delete p;
            //cout << "Destructor"<< (*p) << endl;
        }

        void Release() { // Освобождение ресурсов
            delete p;
            p = nullptr;
        }

        void Print() {
            cout << (*p) << " count - " << count << endl;
        }
};

int main() {
    int* pm = new int(7);
    int* pn = new int(10);
    SmartPointer<int> A(pm);
    SmartPointer<int> B(A);
    SmartPointer<int> C(pn);
    C.Print();
    C = A;
    A.Print();
    B.Print();
    C.Print();
    return 0;
}

Добрый день, объясните пожалуйста ошибку - double free detected in tcache 2. Я понимаю что два объекта ссылаются на один участок памяти, но как этого избежать? Перепробовал кучу вариантов, ничего не получается.

Кирилл
  • 15
  • 1
  • 8
  • 2
    Или не удалять p вовсе (например, у вас нет защиты от передачи указателя на, скажем, переменную в стеке...), или использовать глубокое копирование — выделять память и переписывать туда объект. Но судя по названию (не по функциональности, увы...), вы пытаетесь сделать что-то типа shared_ptr? Так добавьте счетчик... – Harry Aug 18 '23 at 10:05
  • Хочу подобие auto_ptr. – Кирилл Aug 18 '23 at 10:10
  • 2
    Тогда надо запретить копирование, только move. И при переносе не удалять указатель, а просто обнулять. – Harry Aug 18 '23 at 10:33
  • Извините за глупый вопрос, но как это сделать, где об этом прочитать? Если не трудно, можете ссылку скинуть? – Кирилл Aug 18 '23 at 10:40
  • 1
    Счетчик ссылок count должен быть один на управляемый указатель, а тут в каждом объекте SmartPointer отдельный. И память должна освобождаться только когда он достиг 0. – user7860670 Aug 18 '23 at 10:46
  • 1
    Глобально https://ru.stackoverflow.com/q/454263/195342, боюсь ошибиться, но вопрос вот такого указателя, кажется, рассматривался в https://readli.net/sovremennoe-proektirovanie-na-c/ (правда, она достаточно древняя, стандарт языка успел измениться. Но принципы остались прежние.) – Harry Aug 18 '23 at 11:21
  • 1
    Черти что. Если есть счетчик ссылок, то почему вы его в деструкторе не проверяете, и зовете delete независимо от его значения? Да и вообще, счетчик должен быть один на все копии, в куче. Зачем имитировать корявый auto_ptr, если у нас уже давно есть move-семантика, которая позволяет сделать нормально - как в unique_ptr. – HolyBlackCat Aug 18 '23 at 12:41

1 Answers1

0

Смарт поинтер должен хранит указатели лично и при передачи указателя другому экземпляру должен у себя отказаться от контроля. примерно так : p = nullptr ; count = 0 ;
Вот пример рабочий такой:

#include <iostream>

using namespace std;

template <typename T>

class SmartPointer { private: T* p; int count = 0; public:

    SmartPointer( T * &amp; pb ) { // Конструктор !!!
        p = pb;
        pb = nullptr ; // !!!
        count++;
        cout &lt;&lt; &quot;Constructor - &quot; &lt;&lt; (&amp;p) &lt;&lt; count &lt;&lt; endl;
    }

    SmartPointer(SmartPointer &amp; ConPtr) { // !!!
        p = ConPtr.p;
        ConPtr . p = nullptr ; // !!!
        count = ConPtr.count;
        ConPtr.count=0;
        cout &lt;&lt; &quot;Constructor Copy - &quot; &lt;&lt; (&amp;p) &lt;&lt; count &lt;&lt; endl;
    }

    SmartPointer&amp; operator = ( SmartPointer &amp; ConOper) { // !!!
        if (this != &amp;ConOper) {
            Release();
            p = ConOper.p;
            ConOper . p = nullptr ; // !!!
            count = ConOper.count;
            ConOper.count=0;
            cout &lt;&lt; &quot;Reload operator - &quot; &lt;&lt; (&amp;p) &lt;&lt; count &lt;&lt; endl;
        }
        return *this; 
    }

    ~SmartPointer() { // Деструктор
      if ( p ) // !!!
        cout &lt;&lt; &quot;Destructor&quot; &lt;&lt; (*p) &lt;&lt; endl;
      else
        cout &lt;&lt; &quot;Destructor Null&quot; &lt;&lt; endl;  
      delete p;
      //cout &lt;&lt; &quot;Destructor&quot;&lt;&lt; (*p) &lt;&lt; endl;
    }

    void Release() { // Освобождение ресурсов
        delete p;
        p = nullptr;
    }

    void Print() {
      if ( p ) // !!!
        cout &lt;&lt; (*p) &lt;&lt; &quot; count - &quot; &lt;&lt; count &lt;&lt; endl;
      else  
        cout &lt;&lt; &quot;Null count - &quot; &lt;&lt; count &lt;&lt; endl;
    }

};

int main() { int* pm = new int(7); int* pn = new int(10); SmartPointer<int> A(pm); SmartPointer<int> B(A); SmartPointer<int> C(pn); C.Print(); C = A; A.Print(); B.Print(); C.Print(); return 0; }

AlexGlebe
  • 17,227