C ++内存管理引用类型

我仍然是一个相当新手的程序员,我有一个关于c ++内存管理与refence类型的问题。

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

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

谢谢大家!

-R


听起来就像你从C#这样的托管语言接近C ++。 C ++中的事情有点不同。

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

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

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

也许。 如果你像这样创建对象,那将是真实的,例如:

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

MyClass* pObj1 = new MyClass();
MyClass* pObj2 = (MyClass*)malloc( sizeof(MyClass) );

但是,如果你创建这样的对象:

MyClass obj3;

在后者中,对象被分配在堆栈中,并且不存在指针或引用。 你正在操纵它作为“价值类型”。

MyClass *pObj3 = &obj3;

现在pObj3是一个指针(在栈)到obj3 ,这也是在堆栈中。 看到? 类定义与该类的对象之间没有连接。 这取决于你如何使用类型。 将相同类型的基于堆栈和堆的对象组合在一起非常常见。

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

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

C和C ++不会在数组中放置任何不同的语义(有一个例外,我会在第二次提到)。 一旦分配完毕,它们只是一堆碰巧是连续的对象。 这取决于您的程序使用数组操作或直接指针操作来访问单个成员。 这意味着:

  • arrayOfClass[i]((Class*)*(array + i))完全相同。 在C中,你甚至可以对i[arrayOfClass] ,它意味着与arrayOfClass[i]相同(但是C ++会抱怨,因为它有更严格的类型规则)。
  • 您可以使用数组运算符指向不属于数组一部分的对象(可能会崩溃)
  • 您可以对数组上的元素使用普通的指针操作。
  • 您可以通过解释较小的连续内存块来分配“大块”内存和“制作自己的数组”,就好像它们是小对象数组的成员一样(这正是使用malloc()时所得到的结果)。
  • 数组本身不是类型的; 它们只是一种分配多个对象的便捷方法,并且是一种在某些情况下更方便使用指针的方法。

    我认为这个“数组不是特别的”规则的唯一例外是通过new在C ++中分配的数组。 当你通过new分配一个数组时,它会在分配数组时包含有关数组包含的元素的数量(通常在堆的旁边,但这不是强制性的)。 然后,您必须使用特殊的delete []运算符来删除该数组。 delete []查找并使用该额外的信息位以正确删除阵列的所有元素。

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

    只要你正确地做事,是的。

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

    是的free() ,尽管当你调用free()(除void* )时使用指向不同类型的指针是一件非常不寻常的事情。 这些东西有合法用途,但它们是高级主题。 您可能希望让有经验的开发人员查看您的设计,看看它是否真的是一个合适的事情。

    delete是另一回事; 如果您在调用delete时使用与缓冲区中存储的类型不同的类型的指针,则行为为“未定义”(也许您会崩溃)。 这是因为deletefree()所做的更多; 它也调用对象的析构函数方法,编译器依靠指针的类型来调用正确的方法。 如果使用错误的指针类型,将会调用错误的方法,谁知道会发生什么。 您可能会在new 'd'之后将某些“其他”放在缓冲区中,但这可能需要一些不重要的工作量,并且再次成为高级主题。

    另外请注意,您不应该使用malloc()分配,并且免费使用delete ,也不应该使用free()和free分配new和免费的。 确保您的方法已正确配对。

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

    在C ++中,处理这个问题的规范方法是该类应该有一个析构函数,并且析构函数会负责释放指针成员。 在C中,您没有选择,并且在清除外部指针之前必须手动清除指针成员。

    这一切都假定对象拥有成员指针指向的内容。 在像C#这样的托管语言中,所有对象都由运行时“拥有”,并在垃圾回收器的控制下被删除,因此您不必担心它。 在C ++中。 谁拥有由成员指针指向的对象是由程序的语义定义的,而不是语言,并且您必须注意确定何时适合删除嵌入对象。 如果你错过了删除对象的正确时间,你会泄漏内存; 如果过早删除它,则会导致未定义的行为和崩溃(当某些代码尝试使用已被删除的对象时)。

    现在,C ++引用基本上只是一个带有一点糖衣的指针,旨在使某些类型的指针更易于使用。 简单来说,几乎没有任何事情可以通过使用指针来完成,而这些引用无法在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
    

    考虑到你在C ++方面的知识水平,我可能会远离引用,直到你理解C / C ++中的内存管理更好一点。


    我假设删除/释放类对象不释放它的成员指针指向的是,是正确的?

    这是默认情况下正确的,这就是C ++类具有析构函数的原因。 例如:

    class C {
        int* x;
    
    public:
        C () : x (new int[10]) {}  // constructor
    };
    
    C* cptr = new C;  // a pointer to a C object
    

    如果我删除cptr ,将会有内存泄漏,因为x没有被释放。 所以我会添加一个析构函数给C

    class C {
        ...
        ~C () {delete [] x;}  // destructor
    };
    

    (其余问题有很多问题,你似乎混淆了Java和C ++,这就是为什么你的大部分问题没有意义,我只回答这个片段给你一个例子,我建议你阅读一本C ++书籍以更好地理解该语言。)


    我不知道从哪里开始。

    我们有原始类型(例如int)。

    我们有我们的老朋友c结构。

    我们有课。

    所有这些都可以自动进行存储类别; 就坐在栈上。 所有可以通过价值传递。

    然后我们有指向x的指针。 ( x * )。 这些将项目的地址存储在堆栈中,或将其分配到其他地方,就像new 。 一旦你得到了一个指针,这是由你来确保你不做一些无效的事情。 如果从函数返回,则指向其动态上下文中的自动项目的指针将变为无效。 如果你使用delete ,你删除的指针不再有效,当然,它也没有任何拷贝。

    然后,最后,我们有参考。 x&只是语法糖。 传递对某个东西的引用只是将一个指针传递给它。 使用引用类型避免了键入一些*字符的需要,并且它断言表下的指针永远不会为空。

    链接地址: http://www.djcxy.com/p/79103.html

    上一篇: C++ memory management of reference types

    下一篇: Garbage Collector no more references