Хорошо, давайте начнем с небольшого вступления, потому что вы, кажется, не разбираетесь в некоторых вещах, необходимых для понимания умных указателей:
Длительность автоматического хранения: время жизни объектауправляется компилятором.Его время жизни определяется областью действия связанной переменной.
Например:
{
X x; // lifetime of x starts here
// ....
} // lifetime of x ends here
Продолжительность динамического хранения: Время жизни объекта управляется программистом.Он начинается с вызова new
и заканчивается вызовом delete
(это немного упрощается).
Например:
auto foo(X* x)
{
delete x; // lifetime ends with delete
}
{
X* x = new X{}; // lifetime starts with new
foo(x);
}
В C ++ вам никогда не следует явно вызыватьnew
/ delete
и используйте вместо этого умные указатели.
unique_ptr
(если не указано иное) при уничтожении автоматически вызовет delete
на указателе, который он удерживает.Это причина, по которой он должен быть снабжен указателем на динамический объект, т.е. выделен с new
.Это одна из ваших проблем.
X x;
std::unique_ptr<X> p{&x};
// p receives a pointer to an automatic storage duration
// this is 100% wrong. The destructor for x would be called twice
// once as part of the automatic lifetime of x
// and then as part of the destructor of p
// resulting in UB
это то, что вы делаете здесь:
MyClass m = ...;
MyClass * mpointer = &m;
unique_ptr<MyClassParent>(mpointer);
// unique_ptr receives a pointer to an automatic storage duration object
Как будто этого было недостаточно, другая проблема, с которой вы сталкиваетесь, - это доступ к свисающий указатель .
Область действия m
находится в пределах for.Вектор содержит указатели на такие объекты, и эти объекты выходят из области видимости после каждой итерации.Когда вы делаете rv[0]
, вы получаете доступ к объекту, срок жизни которого истек.Опять неопределенное поведение.
Надеюсь, вы лучше понимаете, что делает unique_ptr
и какую проблему он решает.Решение - как показал Сторри Теллер - использовать make_unique
.
Что делает make_unique
: он вызывает new
и создает unique_ptr
из этого указателя, возвращенного new
.Вы можете сделать это вручную, но не должны из-за других проблем: Различия между std :: make_unique и std :: unique_ptr