Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ memory management of reference types

I'm still a fairly novice programmer and I have a question about c++ memory management with refence types.

First of all, my understanding of reference types:

A pointer is put on the stack and the actual data that the pointer points to is created and placed on the heap. Standard arrays and user defined classes are refence types. Is this correct? Second, my main question is do c and c++'s memory management mechanisms (malloc, free and new, delete) always handle this properly and free the memory that a class or array is pointing to? Does everything still work if those pointers get reassigned somehow to other objects of the same size/type on the heap? What if a class has a pointer member that points to another object? I am assuming that delete/freeing the class object doesn't free what it's member pointer points to, is that correct?

Thanks all!

-R

like image 669
Russel Avatar asked Jan 18 '11 02:01

Russel


2 Answers

Sounds like you are approaching C++ from a managed language like C#. Things are a bit different in C++.

What you describe as reference types does not exist in C++. Types in C++ are not 'reference types', nor are they 'value types'. They are just 'types'. Whether they are handled via references (or pointers) or by value depends entirely on the code that uses the type (not the definition of the type). By contrast, in languages like C#, the type declarer decides whether the type must be handled as reference or a value. C++ does have something called a reference but it has nothing to do with the things you describe. I'll mention C++ references at the end.

Now, let's see if we can process the several parts of your question:

A pointer is put on the stack and the actual data that the pointer points to is created and placed on the heap.

Maybe. That would be true if you create the object like this, for example:

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

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

But not if you create the object like this:

MyClass obj3;

In the latter, the object is allocated in the stack and there is no pointer or reference involved. You are manipulating it as a 'value type'.

MyClass *pObj3 = &obj3;

Now pObj3 is a pointer (in the stack) to obj3, which is also in the stack. See? No connection between the class definition and where objects of that class are stored. It depends on how you use the type. It's pretty common to have a combination of both stack and heap based objects of the same type.

Standard arrays and user defined classes are refence types. Is this correct?

No; arrays are just a set of objects of the same type/size placed in consecutive memory locations. The array can be allocated in the stack or in the heap, just like with individual objects.

C and C++ don't place any distinct semantic on arrays (with one exception I'll mention in a second). Once they are allocated, they are just a bunch of objects that happen to be consecutive. It's up to your program to use array operations or direct pointer operations to access the individual members. That means:

  • arrayOfClass[i] is exactly identical to saying ((Class*)*(array + i)). In C, you can even say to i[arrayOfClass] and it means the same as arrayOfClass[i] (C++ however will complain because it has stricter type rules).
  • You can use array operators in pointers to objects that are not part of an array (and likely crash)
  • You can use ordinary pointer operations on elements on an array.
  • You can allocate a 'large' chunk of memory and 'make your own array' by interpreting smaller consecutive pieces of that memory as if they are members of an array of smaller objects (that's exactly what you get when you use malloc()).

Arrays are not types on their own right; they are just a convenient way to allocate multiple objects, and a way to do pointers that is more convenient in some circumstances.

The only exception that comes to my mind to this "arrays are not special" rule is the case arrays allocated in C++ via new. When you allocate an array via new, it leaves information (usually in the heap adjacent to the array, but that is not mandatory) about how many elements the array contained when it was allocated. Then, you must use the special delete [] operator to delete the array. delete [] finds and uses that extra bit of information to delete all of the elements of the array correctly.

Second, my main question is do c and c++'s memory management mechanisms (malloc, free and new, delete) always handle this properly and free the memory that a class or array is pointing to?

As long as you do things correctly, yes.

Does everything still work if those pointers get reassigned somehow to other objects of the same size/type on the heap?

Yes for free(), although using pointers to a different type when you call free() (other than a void*) is a rather unusual thing to do. There are legitimate uses of such things, but they are advanced topics. You might want to have your designed looked at by an experienced developer to see if it really is an appropriate thing to do.

delete is a different matter; if you use a pointer to a type different from what's stored in the buffer at the time you call delete, the behavior is "undefined" (a.k.a. you'll likely crash). That's because delete does more than what free() does; it also calls the object's destructor method, and the compiler relies on the type of the pointer to call the proper method. If you use the wrong pointer type, the wrong method will be called and who knows what will happen. You can potentially put something "else" in the buffer after you new'd it, but that might requires a non-trivial amount of work and is again an advanced topic.

Also note that you should never allocate with malloc() and free with delete, nor should you allocate with new and free with free(). Make sure your methods are properly paired.

What if a class has a pointer member that points to another object? I am assuming that delete/freeing the class object doesn't free what it's member pointer points to, is that correct?

In C++, the canonical way to deal with that is that the class should have a destructor, and the destructor would take care of freeing the pointer member. In C you don't have a choice and you have to clear the pointer member by hand before clearing the outside pointer.

That all assumes that the object owns the contents pointed by the member pointer. In managed languages like C#, all objects are 'owned' by the runtime and deleted under control of the garbage collector, so you don't have to worry about it. In C++. who 'owns' objects pointed by member pointes is defined by the semantics of your program, not the language, and you have to pay attention to decide when is the right time to delete embedded objects. If you miss the right time to delete the object, you leak memory; if you delete it too soon, you get undefined behavior and crashes (when some code tries to use the object that has already been deleted).

Now, a C++ reference is basically just a pointer with a bit of sugar-coating, intended to make certain kind of pointers easier to use. In in priciple, there is almost nothing that you can do with references that you cannot do in C++ by just using pointers; the few exceptions are advanced topics that I'll skip (I would have to look it up to give the topic justice and I don't have my resources at hand).

For your point of view a C++ reference is just a pointer that looks like a stack object.

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

Given your level of knowledge in C++ I might stay away from references for now, until you come to understand memory management in C/C++ a little better.

like image 82
Euro Micelli Avatar answered Oct 05 '22 00:10

Euro Micelli


I am assuming that delete/freeing the class object doesn't free what it's member pointer points to, is that correct?

That's correct by default, which is why C++ classes have destructors. For example:

class C {
    int* x;

public:
    C () : x (new int[10]) {}  // constructor
};

C* cptr = new C;  // a pointer to a C object

If I delete cptr, there will be a memory leak since x isn't freed. So I will add a destructor to C:

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

(There are tons of issues with the rest of your question. You seem to have confused Java and C++, which is why most of your question doesn't make sense. I've answered only this fragment to give you an example of how to free resources automatically. I suggest you read a C++ book to get a better understanding of the language.)

like image 37
chrisaycock Avatar answered Oct 05 '22 01:10

chrisaycock