C++内存管理的引用类型

Rus*_*sel 7 c c++ heap stack memory-management

我仍然是一个相当新手的程序员,我对使用refence类型的c ++内存管理有疑问.

首先,我对参考类型的理解:

指针放在堆栈上,指针指向的实际数据被创建并放在堆上.标准数组和用户定义的类是refence类型.它是否正确?其次,我的主要问题是做c和c ++的内存管理机制(malloc,free和new,delete)总能正确处理这个并释放类或数组所指向的内存吗?如果这些指针以某种方式重新分配给堆上相同大小/类型的其他对象,那么一切仍然有效吗?如果一个类有一个指向另一个对象的指针成员怎么办?我假设删除/释放类对象不释放它的成员指针所指向的,这是正确的吗?

谢谢大家!

-R

Eur*_*lli 16

听起来你正在从像C#这样的托管语言接近C++.C++中的情况有所不同.

您在C++中不存在您描述为引用类型的内容.C++中的类型不是"引用类型",也不是"值类型".他们只是'类型'.它们是通过引用(或指针)还是通过值处理完全取决于使用类型的代码(不是类型的定义).相反,在像C#这样的语言中,类型声明器决定是否必须将类型作为引用或值处理.C++确实有一些称为引用的东西,但它与你描述的东西无关.我最后会提到C++引用.

现在,让我们看看我们是否可以处理您问题的几个部分:

指针放在堆栈上,指针指向的实际数据被创建并放在堆上.

也许.如果您创建这样的对象,那将是真的,例如:

class MyClass { /* ... */ };
...

MyClass* pObj1 = new MyClass();
MyClass* pObj2 = (MyClass*)malloc( sizeof(MyClass) );
Run Code Online (Sandbox Code Playgroud)

但是,如果您创建这样的对象,那就不是:

MyClass obj3;
Run Code Online (Sandbox Code Playgroud)

在后者中,对象在堆栈中分配,并且不涉及指针或引用.您正在将其作为"值类型"进行操作.

MyClass *pObj3 = &obj3;
Run Code Online (Sandbox Code Playgroud)

现在pObj3是一个指针(在堆栈中)obj3,它也在堆栈中.看到?类定义与该类的对象存储位置之间没有任何关联.这取决于您如何使用该类型.将相同类型的堆栈和基于堆的对象组合起来是很常见的.

标准数组和用户定义的类是refence类型.它是否正确?

没有; 数组只是放置在连续内存位置的一组相同类型/大小的对象.数组可以在堆栈中或堆中分配,就像使用单个对象一样.

C和C++没有在数组上放置任何不同的语义(我将在一秒钟内提到一个例外).一旦分配它们,它们就是一堆碰巧连续的对象.您的程序可以使用数组操作或直接指针操作来访问各个成员.这意味着:

  • arrayOfClass[i]完全相同于说((Class*)*(array + i)).在C中,你甚至可以说它i[arrayOfClass]和它意味着相同arrayOfClass[i](但是C++会因为它有更严格的类型规则而抱怨).
  • 您可以在指向不属于数组的对象的指针中使用数组运算符(并且可能会崩溃)
  • 您可以对数组上的元素使用普通指针操作.
  • 您可以通过解释该内存的较小连续部分来分配"大"内存块和"创建自己的数组",就像它们是较小对象数组的成员一样(这正是您使用malloc()时获得的内容).

数组本身不是类型; 它们只是分配多个对象的便捷方式,也是一种在某些情况下更方便的指针方法.

我认为这个"数组不是特殊的"规则的唯一例外是用C++分配的情况数组new.当你通过分配一个数组时new,它会留下信息(通常在数组附近的堆中,但这不是强制性的)关于数组在分配时包含多少元素.然后,您必须使用特殊delete []运算符删除该数组.delete []查找并使用该额外信息来正确删除数组的所有元素.

其次,我的主要问题是做c和c ++的内存管理机制(malloc,free和new,delete)总能正确处理这个并释放类或数组所指向的内存吗?

只要你做得对,是的.

如果这些指针以某种方式重新分配给堆上相同大小/类型的其他对象,那么一切仍然有效吗?

是的free(),虽然在调用free()(除了a之外void*)时使用指向其他类型的指针是一件相当不寻常的事情.这些东西有合法用途,但它们是高级主题.您可能希望由经验丰富的开发人员查看您的设计,看看它是否真的适合做.

delete是另一回事; 如果您使用指向与调用delete时存储在缓冲区中的类型不同的类型的指针,则行为是"未定义的"(也就是说您可能会崩溃).那是因为delete不仅仅是做了什么free(); 它还调用对象的析构函数方法,编译器依赖指针的类型来调用正确的方法.如果使用错误的指针类型,将调用错误的方法,谁知道会发生什么.你可以在缓冲区之后将一些"其他"放在缓冲区中new,但这可能需要一些非常重要的工作,并且再次成为一个高级主题.

另请注意,您永远不应该分配malloc()和免费使用delete,也不应该分配new和免费使用free().确保您的方法正确配对.

如果一个类有一个指向另一个对象的指针成员怎么办?我假设删除/释放类对象不释放它的成员指针所指向的,这是正确的吗?

在C++中,处理它的规范方法是类应该有一个析构函数,而析构函数将负责释放指针成员.在C中你没有选择,你必须在清除外部指针之前手动清除指针成员.

这都假设对象拥有成员指针指向的内容.在像C#这样的托管语言中,所有对象都由运行时"拥有"并在垃圾回收器的控制下被删除,因此您不必担心它.在C++中.成员指针指向的'拥有'对象的人是由程序的语义而不是语言定义的,你必须注意决定何时是删除嵌入对象的正确时间.如果您错过了删除对象的正确时间,则会泄漏内存; 如果你太快删除它,你会得到未定义的行为和崩溃(当某些代码试图使用已被删除的对象时).

现在,C++ 引用基本上只是一个带有一点糖涂层的指针,旨在使某些指针更容易使用.在priciple中,几乎没有什么可以通过使用指针在C++中无法完成的引用; 少数例外是我将跳过的高级主题(我必须查看它以使主题公正,我手头没有我的资源).

对于您的观点,C++引用只是一个看起来像堆栈对象的指针.

CMyClass pObj1 = new CMyClass();
CMyClass& myObject = pObj1;      // Create a reference to the object pointed by pObj1

pObj1->Method1();                // Use the pointer to call Method1
pObj1.Method1();                 // Use the reference to call Method1
Run Code Online (Sandbox Code Playgroud)

鉴于你在C++方面的知识水平,我现在可能远离参考,直到你更好地理解C/C++中的内存管理.