8

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

trincot
  • 317,000
  • 35
  • 244
  • 286
Russel
  • 2,335
  • 3
  • 19
  • 11
  • 6
    You are confusing C++ with Java. Get a proper C++ book, and learn from the beginning. Your Java knowledge does not apply. http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Benjamin Lindley Jan 18 '11 at 02:14
  • Thanks for the answers all. I know my random throwing around of the words malloc, free, new, and delete imply I am mixing them up, but I know the difference. I'm just trying to learn c and c++ at sort of the same time and just threw everything in there. Also, for those people that think I'm mixing up Java stuff, they're close.. It's c# I'm getting mixed up with :) – Russel Jan 18 '11 at 03:04
  • I guess my main point of confusion was how c/c++ creates objects. They are not "reference types" in a c# sense, but rather objects that get shoved onto the stack unless dynamically allocated with say 'new', correct? What about arrays? – Russel Jan 18 '11 at 03:10
  • 1
    @Russel, `C` and `C++` are different languages. Pick one :) –  Jan 18 '11 at 03:11
  • @Russel, read Euro Micelli's post. –  Jan 18 '11 at 03:12
  • 2
    @Russel: Arrays also are on the stack unless allocated dynamically with new or malloc. – Benjamin Lindley Jan 18 '11 at 03:17
  • 1
    @PigBen makes a very good point about array allocation. That is a non-obvious difference with C#. – Euro Micelli Jan 18 '11 at 03:25
  • I'd like to highlight that you should never, *ever*, mix `new` and `free()` or mix `malloc()` and `delete` on the same allocated object, even for trivial classes. `new` and `delete` are not required to use the same heap or the same heap management libraries as `malloc` and `free()`, so mixing the two sets of allocation functions is undefined behavior. *Often* `new`/`delete` are implemented through calls to `malloc()`/`free()`, but that is not guaranteed to be the case and it's easy to create a C++ example where that is not the case. – Euro Micelli Jan 18 '11 at 03:37

6 Answers6

19

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.

Euro Micelli
  • 33,285
  • 8
  • 51
  • 70
3

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.)

chrisaycock
  • 36,470
  • 14
  • 88
  • 125
2

I'm not sure where to start.

We have primitive types (e.g. int).

We have our old friend the c struct.

We have classes.

All of these can be storage class automatic; just sitting on the stack. All can be passed by value.

Then we have pointer-to-x. (x *). These store the address of an item on the stack, or allocated somewhere else, as with new. Once you get a pointer, it's up to you to make sure that you don't do something that invalidates it. If you return from a function, pointers to automatic items in its dynamic context become invalid. If you use delete, the pointer you delete through is no longer valid, and, of course, neither are any copies of it.

Then, finally, we have references. x& is just syntactic sugar. Passing a reference to something is just passing a pointer to it. Using a reference type avoids the need to type some * characters, and it asserts that the pointer-under-the-table will never be null.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
2

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

A pointer is variable which stores the address of another variable. Yes this could be the case. A pointer can always point to the local scope (or stack) or to the free store (heap).

Example :

class Foo{
    public:
    // For Test1 This is in the Stack
    // For Test2 this is in the free store
    int x; 

    // For Test1 the pointer is in the Stack
    // AND -> It points, to where we set it (could be stack or heap)
    // For Test2 the pointer-variable-location is in the Free Store
    // AND -> Similar
    int *y;
}

int main()
{
    // Lies in the Local Scope
    Foo Test1;
    // Test2 Lies in the Local Scope, and contains the address of the 
    // Object, which is now on the Free Store
    Foo *Test2 = new Foo();
}

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?

First of all, try to avoid mixing free and delete. Second, free() gets a pointer and does not check if the pointer provided points to a valid memory location. This means you could try to free non-allocated memory which could cause Seg Faults. A standard example of this is

int main()
{
     int * x; // Points to random
     free(x); // Undefined behaviour
}

Another wrong use of a pointer could be:

int main()
{
     int * x = malloc(sizeof(int) * 10); //Allocate an array of 10
     ++x; // Now points to x[1];
     free(x); // Give me trouble
}

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

yes things can continue working, but this could cause memory leeks. As long as you delete the old stuff, this is fine.

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?

free()ing the class does not call the Destructor, and you can use the destructor to avoid memory leaks. Using delete you can set the destructor to delete that other object, otherwise it will cause memory leaks.

Your post tells me that you confuse some stuff, you start saying about References in C++ but end up talking about pointers and free() and delete, and generally giving the impression that you are confused. I think you should get a good book.

1

Classes aren't necessarily reference types. If for example you had the following code:

class dog {
    int age;
    char *name;
};

int main() {
    int x;
    dog barry;
    ...
}

Then inside main, barry and x would be next to each other on the stack. So the stack would contain two integers and a pointer to a char.

You are right in saying that freeing the object doesn't free the memory its member pointers do. C++ doesn't do any automatic memory management for you so have to be allocate and free everything manually. In this case it'd be best to give dog a destructor, something like

class dog {
    ~dog() {
        delete name;
    }
}

~dog will get called when you delete a dog or when a dog falls out of scope and gets taken off the stack.

Shum
  • 1,236
  • 9
  • 22
0

A reference is basically a constant pointer that uses the syntax of an automatic variable. You can't change what it points to, and you can't use it to delete an object (directly; you can use the address operator on a reference to get a pointer to the referred object, then delete that).

The functions malloc and free just allocate and free blocks of memory. You usually don't need to use these directly in C++. The operators new and delete allocate and free the memory, but they also call the object's constructor and destructor. In a class's constructor all the automatic members' constructors are called, and the same with destructors. If your class has a member that is a pointer, it's memory is not automatically allocated or freed. You have to explicitly do that in the constructor and destructor, or use a smart pointer like std::auto_ptr.

When the delete operator is used on a pointer, the destructor for the pointer type is called, so if you force a pointer to point at the wrong type with explicit casting, then the wrong destructor will be called when you delete it.

Alex
  • 2,152
  • 2
  • 17
  • 20