C ++:在实例化类成员时使用new关键字vs之间的区别?

时间:2011-02-13 04:46:33

标签: c++ memory-leaks memory-management new-operator

对于编程赋值,我们给出了一个模板类,其中两个成员声明不是指针,而是实际对象:

Foo member;

在构造函数中,我最初尝试member = *(new Foo());,但是至少有时候,它知道它正在复制新的Foo对象,因此导致内存泄漏。

我终于发现了member = Foo(),然后抬头看看差异是什么。我了解到,成员将被分配到堆栈而不是堆,并且一旦超出范围,它将被删除。但是这对于对象有什么作用呢?

是否仅在删除父/类对象时删除成员?

我还有一个关于member = *(new Foo());的问题。我正在初始化两个相同类型的成员变量:

// Members
Foo member1;
Foo member2;

// Constructor {
    member1 = *(new Foo());
    member2 = *(new Foo());
}

出于某种原因,似乎member1没有被复制,它保留了与初始Foo相同的地址(即删除时没有内存泄漏)。然而,member2将被复制并具有不同的地址,并且内存被泄露。对此有解释吗?

2 个答案:

答案 0 :(得分:4)

您的分析不正确。这两个都是内存泄漏。您正在做的是分配对象的新副本,将值分配给成员,然后丢弃指向已分配内存的指针,而不释放该内存。在这两种情况下都是内存泄漏。

现在,请考虑以下代码:

class MemberType {
  public:
    MemberType() { std::cout << "Default constructor" << std::endl; }
    MemberType(int) { std::cout << "Int constructor" << std::endl; }
};

class Example1 {
  public:
     Example1() {}
  private:
     MemberType member_;
};

class Example2 {
  public:
      Example2() : member_(5) {}
  private:
      MemberType member_;
};

int main(int argc, char** argv) {
   Example1 example1;
   Example2 example2;
   return 0;
}

此代码将打印两种不同类型的构造函数。请注意,它没有采用任何初始化代码来以默认方式初始化成员。因此,在默认初始化情况下,您的新语句(或甚至没有新的赋值)将是不必要的。使用默认构造函数以外的构造函数初始化成员时,执行此操作的正确方法是使用初始化列表。 (初始化列表是示例中“:member_(5)”所发生的事情。

有关使用C ++构建对象的更多信息,请参阅C++ FAQ on constructors

答案 1 :(得分:2)

member = *(new Foo());

new Foo()动态分配Foo对象并返回指向该对象的指针。 *取消引用指针,为您提供Foo对象。然后将此对象分配给member,其中涉及调用Foo复制赋值运算符。默认情况下,此运算符将右侧(*(new Foo()))对象的每个成员的值分配到左侧对象(member)。

问题是:new Foo()动态分配Foo对象,并且在deletenew返回指针之前,该对象不会被销毁。您不会将该指针保存在任何位置,因此您泄漏了动态分配的对象。

这不是初始化对象的正确方法。

member = Foo();

这会创建一个临时的,已初始化的Foo对象,并且此对象已分配给member。在本声明的最后(有效地在;处),临时对象被销毁。 member未被销毁,临时Foo对象的内容已复制到member,因此这正是您想要做的。

请注意,初始化成员变量的首选方法是使用初始化列表:

struct C {
    Foo member1, member2;

    C() : member1(), member2() { }
};