2017-04-06 147 views
0

我有以下程序 -C++移动的unique_ptr一个struct构件

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

回答

1

实际上,你已经得到了不确定的行为在这里。 你不能将一个malloc'd缓冲区转换为对象类型。构造函数永远不会被调用,并且您的成员变量处于无效状态。

你需要做的要么:

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 - 你需要使用新的布局,以获得正确的行为 - 但通常你不想这样,所以我现在不会详细说明...

2

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

delete c; 

Here是测试(ideone)。

c是一个原始指针。这不是一个聪明的指针。 因此,您必须手动删除它。

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

但是,你自己有malloc,更正确的代码可能是: -

c->~_container(); 

然后free(),但我不认为它是需要在这种情况下,因为CONTAINER不上堆。
(我从来没有使用malloc,所以我不知道这部分。)

编辑:
我的解决方法是快速更新来解决一个问题。 (不打印“销毁”)
另请参阅迈克尔安德森的解决方案。
它解决了另一个底层问题的OP代码。 (malloc的)

EDIT2: Here是关于投放新说迈克尔·安德森提到一个很好的链接。
下面的代码从连杆(带小的修改)复制: -

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.

+0

啊,我明白了。由于malloc'd区域不是“智能”,因此程序不跟踪“c”跟踪跟踪唯一指针范围的方式。 –

+0

@Jai Prabhu是的,我认为这是正确的。 – javaLover

+2

不好 - 比这更糟的是,将一个malloc'd缓冲区转换为具有构造函数的类型是未定义的行为 - 并且该程序允许产生它喜欢的任何垃圾。 –