У меня есть следующая программа —
#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 (), но это не так. Может ли кто-нибудь помочь мне с тем, почему этого не произойдет в этом случае?
У вас здесь на самом деле неопределенное поведение.
Вы не можете просто привести буфер 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, чтобы получить правильное поведение — но обычно вы этого не хотите, поэтому я пока не буду уточнять …
Вы забыли добавить эту строку в конце 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 ++ обычно не рекомендуется.