2014-10-02 146 views
2

我今天看到了一个我不熟悉的new的用法。这是否会造成内存泄漏?

{ 
    string * test = new string("bye"); 
    new (test) string("hello"); 
    cout << *test << endl; //prints "hello" 

    delete test; 
} 

这似乎像它应该在第一,但如果我尝试和“记住”的test初始值,它看起来像记忆被重新分配:

string * test = new string("bye"); 
string * test2 = test; 
new (test) string("hello"); 
cout << *test << endl; //prints "hello" 
cout << *test2 << endl; //also prints "hello" 

这是怎么回事?

+0

我不确定你试图用第二个例子来证明什么。为什么*不会*'cout << * test2'打印你好? – meagar 2014-10-02 02:02:08

+0

放置新的,是的,它泄漏,因为原始对象的析构函数没有运行。 – mythagel 2014-10-02 02:02:21

+0

@megar,因为我已将'test2'分配给'test'的原始值。如果新内存由第二个'new'语句分配,'test'的值应该改变。但事实并非如此。 – 2014-10-02 02:04:05

回答

2

确实存在潜在的内存泄漏,但不是因为您可能会考虑的原因,有两个new和只有一个delete。这其实很好。

问题是第一个字符串的析构函数从未运行。它分配的任何内部存储器都不会被释放。

要解释,第二个new是所谓的放置new。这是在内存中调用已分配的构造函数的一种方法。 new (test) string("hello")的效果是它会覆盖第一个字符串("bye")和另一个字符串("hello") )。展示位置new不会分配更多内存。它只是在现有内存区域上运行string::string(const char *)构造函数。

这就是为什么程序打印hello两次。 testtest2都指向相同的字符串,因此当您覆盖该字符串时,变化将显示在两个变量中。变量本身没有改变,但它们指向的对象具有。

+0

nitpick:如果接受'std :: string *'的operator new'有重载,则不一定返回该指针。说明提供不完整代码的危险性(正如OP所做的那样),以及教授具体内容的危险性(OP可能后来遇到区分很重要的代码)。 – 2014-10-02 02:13:30

+0

是的,你是对的。我已经提出了一个说明,我的答案因教学目的而过于简化。 – 2014-10-02 02:20:52

1

您正在查看的内容称为placement new。它调用已分配内存块的构造函数。

由于原始对象从未被销毁,它肯定会导致内存泄漏。如果没有,这可能是因为短字符串包含在对象本身中,并且不会导致字符串缓冲区的分配。

2

是的,你有(*可能)内存泄漏。不,检查代码没有证明。它演示了两个指针都指向同一个对象。


要理解这一点,注意,std::string一般存储文本的其他地方,因为它动态分配的缓冲区。

因此,当你new一个std::string,至少有两个动态分配:

  • std::string对象本身的动态分配。
  • 该对象的动态分配字符串缓冲区。

内存泄漏与缓冲区有关,由于未运行第一个std::string对象的析构函数,因此缓冲区未释放。


*)“ ”可能的,而不是某些因为std::string,而相比之下,一个std::vector,可以采用在那里将数据直接存储短缓冲器优化。