在阅读了一些教程之后,我仍然不清楚有关C ++内存管理的一些观点。
1。 当使用new运算符声明的类超出范围时,它的析构函数被调用并释放内存吗? 是否有必要调用delete运算符来释放类的内存并将其析构函数调用为?
class Test{};
void newTest(){
Test *t = new Test;
}
int main()
{
newTest();
return 0;
}
2。 使用new关键字声明的变量(例如向量)是否会在它们所在的类被销毁时释放? 是否必须在类的析构函数中显式删除这些变量?
class Test{
vector<int> *vec;
public:
Test();
};
Test::Test(){
*vec = new vector<int>;
}
void newTest(){
Test t;
}
int main()
{
newTest();
return 0;
}
3。 与问题2相同,但在堆栈上声明了常规变量。 在下面的例子中,当t超出范围时,是否删除了向量vec?
class Test{
vector<int> vec;
};
void newTest(){
Test t;
}
int main()
{
newTest();
return 0;
}
4。 最后,这是在类中声明向量的更好方法,通常(在堆栈上)或使用new关键字(在堆上)?
答案 0 :(得分:2)
听起来你可能来自Java背景,因此new
的内容在C ++中的工作方式略有不同。
必须使用new
明确销毁分配有delete
的内存。此示例有内存泄漏。
与问题1类似,您必须删除类析构函数中的内存以回收它。
在这种情况下,矢量将被自动销毁。
在一个班级中,总是喜欢按价值存储成员(而不是新的),除非你有特殊的理由不这样做。仅仅因为它存储在类中的值并不意味着它存在于堆栈中,它与包含类占用的内存区域相同。
最后请注意,在C ++中,您可以使用RAII使内存管理更不容易出错。例如,查看shared_ptr,scoped_ptr和unique_ptr。这些都会在适当的时候自动释放new
分配的内存。
答案 1 :(得分:1)
delete
对象。答案 2 :(得分:1)
new
创建的对象不会自动销毁。您需要明确delete
任何此类对象。new
的任何内存。大多数编写良好的类将在析构函数中为您执行此操作。如果您正在编写该类,请确保清理该类使用的任何内存。答案 3 :(得分:1)
- 当使用new运算符声明的类超出范围时,它的析构函数被调用并释放内存吗?是否有必要调用delete运算符来释放类的内存并将其析构函数调用为?
醇>
变量是对象或指针(没有使用新指针声明clas) 当对象超出范围时,对象会自动销毁 指针 NOT 会自动删除。
void newTest()
{
Test t; // t created here and automatically destroyed.
}
void newTest()
{
std::auto_ptr<Test> t(new Test()); // t created here and automatically destroyed.
// Which will call delete on the contained pointer.
}
您声明的指针超出范围,但内存是析构函数未被调用且内存泄漏。您需要手动完成(或使用我指出的技术之一)。
- 使用new关键字声明的变量(例如向量)是否会在其所在的类被销毁时释放?是否必须在类的析构函数中明确删除这些变量?
醇>
您的意思是pointers initialized with new
,而不是declared with the new keyword
没有。您必须在析构函数中手动调用destroy。但最好不要在课堂上有指针。而是在类中声明一个矢量对象,然后它将被自动销毁。
class Test
{
vector<int> vectorObject;
std::auto_ptr<vector<int> > vectorPtrInSmartPointer;
vector<int>* vectorRaw
public:
Test();
~Test();
private:
Test(Test const& copy);
Test& operator=(Test const& copy);
};
Test::Test()
: vectorPtrInSmartPointer(new vector<int>()) // Need to initialize the smart pointer.
, vectorRaw(new vector<int>) // Need to initialize the RAW pointer
{
// Note the vectorObject was automatically created.
}
Test::~Test()
{
delete vectorRaw; // Need to manually release the RAW pointer.
}
// Smart pointer and object auto released.
注意:
因为类Test包含RAW指针(vector *),所以我必须手动禁用复制构造函数Test::Test(Test const&)
和赋值运算符Test& operator=(Test const&)
。这是为了确保遵循规则3。
- 与问题2相同,但在堆栈上声明了常规变量。在以下示例中,当t超出范围时,是否删除了向量vec?
醇>
是
- 最后,哪个是在类中声明向量的更好方法,通常(在堆栈上)或使用new关键字(在堆上)?
醇>
调用堆栈/堆会掩盖细节(因为成员可能是动态分配对象的自动成员)。更喜欢将它们视为automatic variables
和dynamic variables
。当它们的包含范围被销毁时,automatic variables
会被自动销毁。因此,对于函数变量,这意味着当您离开函数时。对于类成员,这意味着对象被销毁。选择是优先使用automatic variables
(即不用新分配)。
答案 4 :(得分:0)
这两个简单的规则应该回答所有问题:
delete
应与new
一样多。答案 5 :(得分:0)
您应该更喜欢说对象具有动态存储而不是“在堆上”。同样,使用“自动存储”而不是“在堆栈上”。
前者实际上用于标准,而后者更通俗。
如果对象具有自动存储,则当对象超出范围时(在包含块的末尾),编译器将自动调用其析构函数。
需要明确释放分配有new
的内存。将回收实际指针的存储空间,但不会回收它指向的对象。
因此,如果您使用new
,则需要匹配delete
。 new[]
需要与delete[]
匹配。
(“智能指针”非常有用,因为它有助于减轻您跟踪new
和delete
的问题。查找它!)。
销毁一个向量(如果使用new分配,则通过删除,或者如果自动将其保留为范围)将调用其元素的析构函数。这就是为什么我们应该成为持有多个对象的首选方式。
结论:
如果可能,尝试使用智能指针或集合。
否则,请确保delete
new
。 (如果你编写一个类,在构造函数中分配任何动态成员并在类'析构函数中删除它们。)