уникальный ptr — C ++, перемещающий unique_ptr в член структуры

У меня есть следующая программа —

#include <iostream>
#include <memory>

class Person
{
public:
Person(const std::string& name):
name(name) { }

~Person() { std::cout << "Destroyed" << std::endl; }

std::string name;
};

typedef struct _container
{
std::unique_ptr<Person> ptr;
}CONTAINER;

void func()
{
CONTAINER* c = static_cast<CONTAINER*>(malloc(sizeof(CONTAINER)));
std::unique_ptr<Person> p(new Person("FooBar"));
c->ptr = std::move(p);
std::cout << c->ptr->name << std::endl;
}int main()
{
func();
getchar();

return 0;
}

Программа печатает «FooBar». Я ожидаю, что программа выведет «Destroyed» при возврате func (), но это не так. Может ли кто-нибудь помочь мне с тем, почему этого не произойдет в этом случае?

0

Решение

У вас здесь на самом деле неопределенное поведение.
Вы не можете просто привести буфер malloc к типу объекта. Конструкторы никогда не вызываются, и ваши переменные-члены находятся в недопустимом состоянии.

Вам нужно сделать либо:

void func()
{
CONTAINER c;
std::unique_ptr<Person> p(new Person("FooBar"));
c.ptr = std::move(p);
std::cout << c.ptr->name << std::endl;
}

Или же

void func()
{
CONTAINER * c = new CONTAINER();
std::unique_ptr<Person> p(new Person("FooBar"));
c->ptr = std::move(p);
std::cout << c->ptr->name << std::endl;
delete c;
}

или если вы действительно хотите использовать malloc — вам нужно использовать размещение new, чтобы получить правильное поведение — но обычно вы этого не хотите, поэтому я пока не буду уточнять …

1

Другие решения

Вы забыли добавить эту строку в конце func(),

delete c;

Вот это тест (идеон).

c это необработанный указатель Это не умный указатель.
Таким образом, вы должны удалить его вручную.

Удаление c автоматически удалит CONTAINER::ptr так как CONTAINER::ptr это уникальный указатель.

Тем не менее, у вас есть malloc сами, более правильный код может быть:

c->~_container();

затем free(), но я не думаю, что это необходимо в этом случае, потому что CONTAINER не в кучу.
(Я никогда не использовал mallocтак что я не уверен насчет этой части. )

Редактировать:
Мое решение — быстрый патч для решения одной проблемы. (не печатать «Уничтожено»)
Пожалуйста, прочитайте также Майкл Андерсонрешение.
Это обращается к другому лежащий в основе выдача кода ОП. (ТаНос)

Edit2:
Вот хорошая ссылка о размещении новых, что Майкл Андерсон упоминается.
Код ниже скопирован из ссылки (с небольшими изменениями):

int main(int argc, char* argv[]){
const int NUMELEMENTS=20;
char *pBuffer = new char[NUMELEMENTS*sizeof(A)];
//^^^ difference : your "CONTAINER" could be char[xxxx] (without new)
A *pA = (A*)pBuffer;
for(int i = 0; i < NUMELEMENTS; ++i) {
pA[i] = new (pA + i) A();
}
printf("Buffer address: %x, Array address: %x\n", pBuffer, pA);
// dont forget to destroy!
for(int i = 0; i < NUMELEMENTS; ++i){
pA[i].~A();
}
delete[] pBuffer;//<--- no need to delete char[] if it is a stack variable
return 0;
}

Для получения более подробной информации, пожалуйста, смотрите ссылку выше (потому что я не хочу копировать больше здесь).

Вот еще одна полезная ссылка: Использование malloc в C ++ обычно не рекомендуется.

2

По вопросам рекламы [email protected]