【问题标题】:C++ moving a unique_ptr to a struct memberC++ 将 unique_ptr 移动到结构成员
【发布时间】:2017-04-06 02:58:53
【问题描述】:

我有以下程序 -

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

【问题讨论】:

    标签: c++ unique-ptr stdmove


    【解决方案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 来获得正确的行为 - 但通常你不希望这样,所以我现在不会详细说明......

    【讨论】:

      【解决方案2】:

      您忘记在func() 末尾添加这一行。

      delete c;
      

      Here 是测试(ideone)。

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

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

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

      c->~_container();
      

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

      编辑:
      我的解决方案是解决单个问题的快速补丁。 (不打印“销毁”)
      另请阅读 Michael Anderson 的解决方案。
      它解决了 OP 代码的另一个潜在问题。 (malloc)

      编辑2: HereMichael 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.

      【讨论】:

      • 啊,我明白了。由于 malloc 的区域不是“智能”的,因此程序不会像跟踪唯一指针的范围那样跟踪“c”。
      • 不——比这更糟糕的是,将 malloc 的缓冲区强制转换为具有构造函数的类型是未定义的行为——并且允许程序产生它喜欢的任何垃圾。
      • @Michael Anderson 谢谢。我必须说我同意你的看法。
      猜你喜欢
      • 1970-01-01
      • 2021-01-25
      • 2013-03-27
      • 1970-01-01
      • 2014-10-19
      • 2014-07-21
      • 1970-01-01
      • 1970-01-01
      • 2018-10-02
      相关资源
      最近更新 更多