#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
функциональности здесь.