C ++将unique_ptr移动到struct成员

时间:2017-04-06 02:58:54

标签: c++ unique-ptr stdmove

我有以下程序 -

#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()返回时打印“Destroyed”,但事实并非如此。有人可以帮我解释为什么在这种情况下不会发生这种情况吗?

2 个答案:

答案 0 :(得分:2)

您忘记在func()的末尾添加此行。

delete c;

Here是测试(ideone)。

c是一个原始指针。它不是一个智能指针。 因此,您必须手动删除它。

删除c会自动删除CONTAINER::ptr,因为CONTAINER::ptr是唯一指针。

但是,您自己malloc,代码可能更合适: -

c->~_container();

然后free(),但我不认为在这种情况下需要它,因为CONTAINER不在堆上。
(我从未使用malloc,所以我不确定这一部分。)

修改
我的解决方案是解决单个问题的快速补丁。 (不打印“被毁”)
另请阅读 Michael Anderson 的解决方案 它解决了OP代码的另一个底层问题。 (malloc)

<强> EDIT2: Here是关于 Michael Anderson 提及的新位置的良好链接。
下面的代码是从链接中复制的(几乎没有修改): -

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;
}

有关详细信息,请参阅以上链接(因为我不想将更多内容复制到此处)。

这是另一个有用的链接:Using malloc in C++ is generally not recommended.

答案 1 :(得分:1)

你实际上在这里有未定义的行为。 你不能只将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来获得正确的行为 - 但通常你不想这样做,所以我现在不会详细说明......