涉及类析构函数和删除运算符的一些内存管理问题
A few memory management questions involving class destructors and delete operator?
在阅读了一些教程后,我仍然不清楚有关C++内存管理的一些要点。
1.当使用 new 运算符声明的类超出范围时,是否调用其析构函数并释放内存?是否有必要调用 delete 运算符来释放类的内存并调用其析构函数?
class Test{};
void newTest(){
Test *t = new Test;
}
int main()
{
newTest();
return 0;
}
阿拉伯数字。当变量(如向量(所在的类被销毁时,是否释放了使用 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 关键字(在堆上(?
听起来你可能来自Java背景,所以new
的事情在C++中的工作方式略有不同。
- 使用
new
分配的内存必须使用delete
显式销毁。此示例存在内存泄漏。与问题 1 类似,必须删除类析构函数中的内存才能回收它。
在这种情况下,矢量将自动销毁。
在类中,始终更喜欢按值存储成员(而不是按值存储成员(,除非您有其他特定原因。仅仅因为它在类中按值存储并不意味着它在堆栈上,它位于包含类占用的同一内存区域中。
最后请注意,在C++中,您可以使用RAII使内存管理不易出错。例如,看看shared_ptr、scoped_ptr和unique_ptr。这些都处理在适当的时候自动释放new
分配的内存。
- 否,不调用析构函数,也不释放内存。 您必须
delete
对象。 - 否,变量未释放。您必须在析构函数中删除它们。
- 是的,vec 被删除(调用析构函数并释放内存(。
- 如果可能的话,通常在堆栈上更好。例如,如果将对象的所有权传递给另一个对象,则可能无法实现。此外,不应在堆栈上分配太多内存(操作系统对此有限制(,在这种情况下,应在堆上分配对象。
- 否,当指针超出范围时,使用
new
创建的对象不会自动销毁。您需要显式delete
任何此类对象。 - 同样的答案。必须显式释放分配了
new
的任何内存。大多数编写良好的类都会在析构函数中为您执行此操作。如果要编写类,请确保清理类使用的任何内存。 - 此对象会自动为您销毁。而且,如果它写得很好,它会自动销毁它分配的任何内存。
- 大多数类实例应分配为局部变量,因为这将确保自动为您清理它们。但是,如果您需要全局或作为类的一部分,则需要适当地声明它们。
您应该更愿意说对象具有动态存储,而不是"在堆上"。同样,使用"自动存储"而不是"在堆栈上"。
前者实际上是在标准中使用的,而后者则更口语化。
如果对象具有自动存储,则编译器将在对象超出范围(在包含块的末尾(时自动调用其析构函数。
需要显式释放分配new
的内存。将回收实际指针的存储,但不回收它指向的对象。
因此,如果您使用new
则需要具有匹配的delete
。new[]
需要与delete[]
匹配。
(一个非常有用的"智能指针",因为它将帮助您减轻跟踪new
和delete
的麻烦。
销毁向量(如果分配了 new 则通过删除,或者如果 auto,则通过 void(将调用其元素的析构函数。这就是为什么我们应该首选的方式来保存多个对象。
结论:
如果可能,请尝试使用智能指针或集合。否则,请确保您delete
您new
的内容。(如果你编写一个类,在构造函数中分配任何动态成员,并在类的析构函数中删除它们。
- 当使用 new 运算符声明的类超出范围时,是否调用其析构函数并释放内存?是否有必要调用 delete 运算符来释放类的内存并调用其析构函数?
首先是一些术语:
变量是对象或指针(clas 不是用新指针声明的(。
当对象超出范围时,它们会自动销毁。
指针不会自动删除。
第二种首选对象而不是指针
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.
}
回答问题1:
您声明的指针超出范围,但未调用内存析构函数,并且内存泄漏。您需要手动执行此操作(或使用我指出的技术之一(。
- 当变量(如向量(所在的类被销毁时,是否释放了使用 new 关键字声明的变量(例如向量(?是否必须在类的析构函数中显式删除这些变量?
术语
你的意思是pointers initialized with new
而不是declared with the new keyword
回答问题2。
不。必须在析构函数中手动调用销毁。但最好不要在类中设置指针。而是在类中声明一个向量对象,然后它将被自动销毁。
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 指针(矢量*(,我不得不手动禁用复制构造函数Test::Test(Test const&)
和赋值运算符Test& operator=(Test const&)
。这是为了确保遵循 3 法则。
- 与问题 2 相同,但在堆栈上声明了正常变量。在以下示例中,当 t 超出范围时,矢量 vec 是否被删除?
是的。
- 最后,在类中声明向量的最佳方法是通常(在堆栈上(还是使用 new 关键字(在堆上(?
将其称为堆栈/堆会掩盖细节(因为成员可能是动态分配对象的自动成员(。宁愿将它们视为automatic variables
和dynamic variables
。当automatic variables
的包含范围被破坏时,它们会自动销毁。因此,对于函数变量,这意味着当您离开函数时。对于类成员,这意味着当对象被销毁时。选择是更喜欢使用automatic variables
(即不与新的分配(。
这两个简单的规则应该回答所有问题:
- 您应该在代码中具有尽可能多的
delete
new
。 - 尽可能从堆栈而不是堆中分配。
- 当vector是tje全局变量时,c++中vector的内存管理
- 我有一个线程 1:EXC_BAD_ACCESS(代码 = 1,地址 = 0x8)错误.我认为这是由于内存管理不好.我可以
- C++将字符串传递给 C 库以进行内存管理
- 从函数返回时C++内存管理
- 函数指针和 lambda 的内存管理
- 自定义内存管理器在发布模式下工作正常,但在调试模式下则不然
- C++中的内存管理
- C和C++中的内存管理有什么区别
- 字符 * 未从重载运算符或内存管理问题正确返回
- 如何在源代码中使用执行策略检测 C++17 的扩展内存管理算法的可用性?
- 底层指针和内存管理
- 智能指针,避免使用QNetworkAccessManager时进行手动内存管理
- c++中的内存管理问题
- 使用矢量时的内存管理
- 循环和内存管理中的指针算术C++?
- C++堆栈内存管理问题
- C 内存管理中的课程如何管理 - 研究
- 不可变数据模型的内存管理
- C++ 使用数组初始化时的 STL 向量内存管理
- SFML 纹理内存管理