Как память освобождается в shared_ptr с помощью operator=?

#c #c 11 #shared-ptr #smart-pointers

#c #c 11 #shared-ptr #интеллектуальные указатели

Вопрос:

Я новичок в c , я изучал концепцию shared_ptr. Я также понял, что нескольким объектам shared_ptr может принадлежать один и тот же объект, и объект уничтожается, а его память освобождается, когда происходит одно из следующих событий:

1. последний оставшийся shared_ptr, владеющий объектом, уничтожается; 2. последнему оставшемуся shared_ptr, владеющему объектом, присваивается другой указатель с помощью operator= или reset() .

Но когда я попытался выполнить пример программы

      class Rectangle { 
        int length; 
        int breadth; 

        public: 
            Rectangle(int l, int b) 
            { 
              length = l; 
              breadth = b; 
            } 

            int area() 
            { 
                return length * breadth; 
            } 
          }; 

          int main() 
         { 

              shared_ptr<Rectangle> P1(new Rectangle(10, 5)); 
              cout << P1->area() << endl; 

              shared_ptr<Rectangle> P2; 
              P2 = P1;  //how is this possible 

             // This'll print 50 
             cout << P2->area() << endl; 

             // This'll now not give an error, 
             cout << P1->area() << endl; 
             cout << P1.use_count() << endl; 
             return 0; 
            } 
 

После «P2=P1» память, выделенная для P1, должна быть освобождена правильно?
Но все же мы можем напечатать P1->area() .
Пожалуйста, объясните, как это происходит?

Ответ №1:

2. последнему оставшемуся shared_ptr, владеющему объектом, присваивается другой указатель с помощью operator= или reset().

ДА.

После «P2=P1» память, выделенная для P1, должна быть освобождена правильно?

Нет. Это могло бы случиться P2 , если бы это указывало на что-то. Нет P1 .

Логика, лежащая в основе правила (2), заключается в том, что присваивание перезаписывает значение первого операнда, поэтому первый операнд больше не будет указывать на то, что он использовал. Если это был последний указатель на что-то, то больше ничто не будет указывать на это, и оно может быть удалено.

Ответ №2:

То, что вы узнали об уничтожении общих указателей, верно. Но здесь вы не уничтожаете P1 . Вместо этого вы присваиваете P1 P2 . Реализация shared_ptr имеет перегруженный оператор присваивания копии, позволяющий выполнять эту операцию и делающий ее правильной.

Благодаря этой перегруженной реализации P2 теперь общий указатель указывает на тот же объект, P1 что и — оба указателя обращаются к одному и тому же объекту, поэтому вы печатаете одни и те же области. Оба они существуют в допустимом состоянии, и, как вы видите, количество указателей, управляющих этим Rectangle объектом, равно 2.

Определение перегруженного = согласуется с концепцией shared_ptr — существует несколько указателей, указывающих на (из-за) один и тот же объект. Если вы хотите увидеть контрастную реализацию, посмотрите unique_ptr — это интеллектуальный указатель, который предполагает, что только один указатель имеет право собственности на объект. Он также имеет перегруженный оператор присваивания, но его использование приведет к недействительности P1 (насколько мне известно, он установил бы его nullptr таким образом, чтобы он все еще находился в допустимом состоянии, просто ни на что не указывая). P2 был бы единственным владельцем Rectangle . Стоит попробовать, для лучшего понимания.

Вы можете найти более подробную информацию о shared_ptr функциональности здесь.