对于编程赋值,我们给出了一个模板类,其中两个成员声明不是指针,而是实际对象:
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
将被复制并具有不同的地址,并且内存被泄露。对此有解释吗?
答案 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
对象,并且在delete
从new
返回指针之前,该对象不会被销毁。您不会将该指针保存在任何位置,因此您泄漏了动态分配的对象。
这不是初始化对象的正确方法。
member = Foo();
这会创建一个临时的,已初始化的Foo
对象,并且此对象已分配给member
。在本声明的最后(有效地在;
处),临时对象被销毁。 member
未被销毁,临时Foo
对象的内容已复制到member
,因此这正是您想要做的。
请注意,初始化成员变量的首选方法是使用初始化列表:
struct C {
Foo member1, member2;
C() : member1(), member2() { }
};