C++ 将 unique_ptr 移动到结构成员
C++ moving a unique_ptr to a struct member
我有以下程序-
#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"。我希望程序在 func() return 时打印 "Destroyed" 但它没有。有人可以帮我解释为什么在这种情况下不会发生这种情况吗?
您忘记在 func()
末尾添加此行。
delete c;
Here是测试(ideone)。
c
是原始指针。它不是智能指针。
因此,您必须手动删除它。
删除c
会自动删除CONTAINER::ptr
,因为CONTAINER::ptr
是一个唯一指针。
但是,您自己有 malloc
,更合适的代码可能是 :-
c->~_container();
然后free()
,但我认为在这种情况下不需要它,因为CONTAINER
不在堆上。
(我没用过malloc
,所以这部分不太清楚。)
编辑:
我的解决方案是解决单个问题的快速补丁。 (不打印"Destroyed")
另请阅读 Michael Anderson 的解决方案。
它解决了 OP 代码的另一个 底层 问题。 (malloc)
编辑2:
Here 是一个很好的 link 关于 Michael Anderson 提到的新位置。
下面的代码是从 link 复制而来的(稍作修改):-
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;
}
更多细节,请看上面link(因为我不想复制更多到这里)。
这是另一个有用的 link :Using malloc in C++ is generally not recommended.
你实际上在这里有未定义的行为。
您不能只是将 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 - 你需要使用 placement new 来获得正确的行为 - 但通常你不想要那个,所以我现在不会详细说明...
我有以下程序-
#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"。我希望程序在 func() return 时打印 "Destroyed" 但它没有。有人可以帮我解释为什么在这种情况下不会发生这种情况吗?
您忘记在 func()
末尾添加此行。
delete c;
Here是测试(ideone)。
c
是原始指针。它不是智能指针。
因此,您必须手动删除它。
删除c
会自动删除CONTAINER::ptr
,因为CONTAINER::ptr
是一个唯一指针。
但是,您自己有 malloc
,更合适的代码可能是 :-
c->~_container();
然后free()
,但我认为在这种情况下不需要它,因为CONTAINER
不在堆上。
(我没用过malloc
,所以这部分不太清楚。)
编辑:
我的解决方案是解决单个问题的快速补丁。 (不打印"Destroyed")
另请阅读 Michael Anderson 的解决方案。
它解决了 OP 代码的另一个 底层 问题。 (malloc)
编辑2:
Here 是一个很好的 link 关于 Michael Anderson 提到的新位置。
下面的代码是从 link 复制而来的(稍作修改):-
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;
}
更多细节,请看上面link(因为我不想复制更多到这里)。
这是另一个有用的 link :Using malloc in C++ is generally not recommended.
你实际上在这里有未定义的行为。 您不能只是将 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 - 你需要使用 placement new 来获得正确的行为 - 但通常你不想要那个,所以我现在不会详细说明...