views:

201

answers:

9

When using C++, if there is a class:

class MyClass
{
    char memory1bye;
    int memory4bytes;
    int another4bytes;
};

this class uses total of 9 bytes at memory… so if i do something like:

MyClass *t1;

This will give me a usable address for the Class, but will it allocate the 9 bytes? And will it call default constructor? Or do I need to malloc those 9 bytes to the class? If then I called something like:

t1 = (MyClass *)new MyClass;

will it be considered memory leak? In other words, what happens to the old address?

+13  A: 
  1. Do not make assumptions about the size of data-types, they are implementation dependent.
  2. MyClass *t1 defines an uninitialized pointer. Dereferencing it invokes undefined behavior.
  3. t1 = (MyClass *)new MyClass; allocates memory on the heap and creates a new object. If this memory does not get deallocated using delete, there will be a memory leak. Also, you do not need the cast there, t1 = new MyClass(); suffices.

Edit: About allocation.

MyClass *t1 = NULL; 

declares a pointer to a MyClass-object, but it does not create the object. This pointer is initialized to point to 0. Now when you do

t1 = new MyClass();

the operator new creates a new instance of MyClass and assigns the address of that object to t1. You can now work with that object through t1:

t1->doStuff();

You can even create more pointers that point to the same object:

MyClass *t2 = t1;

Now t2 and t1 point to the same object. When you are done with the object, just do:

delete t1;

(delete t2 would have the same effect). Now the object is destroyed, but the pointers still point to the same address (which is not safe anymore). Doing

t2->doStuff();

after the delete invokes undefined behavior. If we go back to before the delete, consider this:

t1 = NULL;
t2 = NULL;

Now we do not have the address of the object we created anymore, so we cannot call delete on it. This creates a memory leak. This hopefully gives you some understanding of what is going on. Now forget all this and read about RAII.

Space_C0wb0y
wow, I had the same answer, but yours is better formatted.
stefaanv
Additionally you can mention that the casting in the `new` is not requied.
Naveen
so basicly changing the t1 to another address is not considered memory leak because t1 is just a pointer to empty space ?
VirusEcks
@VirusEcks: The result of a [new expression](http://stackoverflow.com/questions/2697892/what-is-return-type-of-new-in-c/2697929#2697929) is an object on the heap. Such objects are to be deleted by invoking operator `delete` on them, which is done by passing their address to `delete`. Addresses are stored in pointers. A leak is if you lose your last reference (pointer) to an object on the heap.
sbi
@VirusEcks: I added some explanation that I hope will help you understand what's going on.
Space_C0wb0y
@Space_C0wb0y ,.. Thanks .. makes sense
VirusEcks
+1  A: 

Don't assume that MyClass uses 9 bytes, it depends by the machine and by the compiler!

MyClass *t1;

That will give you a usable pointer, but the space to hold class has not been allocated. So the answer to the first two questions is NO.

And yes, you have to allocate space for the class for yourself, if you want to use the pointer. Of course you could get rid of memory allocations by creating MyClass on the heap*:

MyClass t1 ();

And that memory will be automatically released when t1 goes out of scope.

  • I meant: stack.
vulkanino
MyClass t1(); will be on the stack, not the heap.
Scott Langham
`MyClass t1 ();` doesn't create any object, it is a declaration of a function prototype. Also, the statement "you could get rid of memory allocations by creating MyClass on the heap" is wrong, I think you meant on the stack.
Naveen
"Of course you could get rid of memory allocations by creating MyClass on the heap". I guess by "heap" you mean "stack". Also, `MyClass t1 ();` doesn't define an object. It declares a function.
sellibitze
yes, I meant stack, thanks for pointing it out, I'm editing my answer.
vulkanino
+3  A: 

Just declaring a pointer will not allocate memory to hold the class, and it will not call a constructor. You have to call the operator new to actually allocate memory and provide object initialization. Also, there is no need to cast the return type of new.

Oh, and I'm also obliged to tell you that in C++, you should almost always look for other ways than manually managing memory, these being container classes (std::vector, std::deque and the like) and smart pointers, both of which make managing memory a lot less painful.

Jim Brissom
+2  A: 
MyClass* t1;

This doesn't actually allocate the memory for a MyClass object. Your variable is only a pointer with the potential to track the memory address of MyClass objects, but no such object is being created yet, and the pointer isn't being set to point anywhere.

(Of course, some memory is allocated for the pointer itself, but that's on the stack if this statement is inside a function, or global otherwise.)

t1 = (MyClass*)new MyClass;

This is the right kind of thinking for creating a MyClass instance. Still, the best way is usually to do it on the stack:

MyClass t;  // who needs a pointer?

Then you don't have to even think about the memory. The disadvantage is that the object only exists until you leave the scope it was created in, as indicated by the nesting of { and }.

If you want the object to live longer then you really do need it on the heap (or can make it a static / global variable). For dynamic allocation on the heap just use:

t1 = new MyClass;

You don't need - or want - to explicitly cast the returned pointer to MyClass*... it's just redundant and a potential source of bugs if you change the class name in one place but not another.

Some time later, you'll want to delete t1 too.

The actual size of MyClass may not be 9 bytes.. it depends on the compiler, and may be a function of compiler command line flags, compiler version, target memory model, OS etc..

Tony
+1 for mentioning the stack (migrating Java-programmers often don't know about it).
Space_C0wb0y
+1  A: 

If you do something like

MyClass *t1;

you are just declaring a pointer to a class MyClass. You are not really allocating any memory. In order to create an instance of that class you can use any of these:

MyClass t2;                  // this calls a default constructor implicitly
MyClass t3 = MyClass();      // this also calls a default constructor explicitly
MyClass *t4 = new MyClass;   // calls default constructor implictly

the two first declarations use automatic storage whilst the last one uses dynamic storage. If you define a parameterized constructor for your class the declarations would be something like this:

MyClass t5(arg1, arg2, arg3);
MyClass t6 = MyClass(arg1, arg2, arg3);
MyClass *t7 = new MyClass(arg1, arg2, arg3);
Vintharas
good answer .. but didn't cover all the questions :/
VirusEcks
+2  A: 

In addition to some of the other answers:

  1. The "size" of a class is influenced by many things:

    • The implementation-defined size of the member variables
    • The vtable
    • Memory alignment requirements of the member variables
    • Padding

  2. While the cast is unnecessary, it's also bad C++ style. Prefer not to use the C-style cast, but use one of the other, safer (or at least more explicit) casts from C++:

    • dynamic_cast<type>()
    • static_cast<type>()
    • reinterpret_cast<type>()

For more information see C++ Reference Guide - New C++ Cast Operators

MadKeithV
+1  A: 

-There is no guarantee that this class object will occupy 9 bytes. This is completely implementation specific behavior

-MyClass *ptr just declares a pointer to 'MyClass' type. It does not point to any object of type 'MyClass' yet. If it is global it will be zero initialized, else if such a pointer is local (e.g. function scope) it will be uninitialized.

-You need to initialize this pointer to point to a 'MyClass' object

e.g. assuming that 'm' is an object of type 'MyClass'

MyClass m; 
ptr = &m;       // this does not create any new object(no constructor runs)

OR

MyClass *ptr;
ptr = new MyClass();  // This new expression, allocates memory large 
                      // enough to hold a 'MyClass' object, initializes
                      // the object by running it's constructor

delete ptr;           // delete the MyClass object by running it's 
                      // destructor, return the allocated memory back
                      // to the implementation

-If you don't delete the pointer 'ptr' after doing a new, it is a memory leak for sure

Chubsdad
A: 

The class may not be 9 bytes. It could be more if the compiler rounds up by padding the structure to make it fit the computers architecture better.

MyClass *t1; does not give you a usable address. It is an uninitialized pointer that points to a random memory location, and there's no telling what could be at that address. It does not allocate you any space to store a MyClass instance and will not call a constructor. I recommend you initialize pointers when you define them:

MyClass *t1 = 0;   // use 0, NULL, or null_ptr

You need to reserve space for the class and call the constructor. 'new' does both of these for you.

MyClass *t1 = new MyClass();

Don't forget you need a 'delete' to match every new otherwise you'll be writing a memory leak.

Scott Langham
+1  A: 
  1. As many people have said, the size of MyClass is implementation-dependent. In this case, because the class has no methods, you've basically got a struct so it is possible to make some reasonable guesses as to size. On a normal modern 32-bit machine without any unusual compiler flags, the size of the structure will be 12 bytes; this follows from the fact that fields are aligned to 4-byte boundaries by default on current architectures.

    On a 64-bit machine it could be even larger, but I'd be a bit surprised if it was bigger than 24 bytes (i.e., 8-byte alignment for each field). I don't think anything uses anything larger than 8-byte alignment for fields unless explicitly told to, and there's not much point in using larger alignment values for fields as the memory allocation functions themselves usually have 8-byte alignment. (NB: Don't count on that being true for your machine!)

    The only way to actually know the size of anything is to use sizeof(MyClass). You hardly ever need to use that in C++, as the new operator knows about that for you and allocates the amount of space needed. And as previously noted, remember that sizes of anything (other than char) are not portable, even if they don't actually vary gratuitously.

  2. Doing MyClass *t1; doesn't allocate anything. It just gives you a place to store the address of an object (specifically, a MyClass instance). By default, that space points off into la-la land if the variable is in any local scope or in a class or structure definition. If you're not about to put an address in the variable, it's probably a good idea to explicitly initialize it to NULL so that it at least points to a definite not-an-object.

  3. Your t1 = (MyClass *)new MyClass; contains an unnecessary cast, since new returns a pointer to an object of that type anyway. Doing t1 = new MyClass; is enough.

  4. If t1 was previously pointing to an object and was the only variable pointing to it, you'll have a memory leak (assuming you've not used a garbage collector library; most C++ programs are written without using them). If something else is pointing to the object, then that had better be assuming the responsibility for cleaning it up. If the address isn't pointing to anything in particular, or it was pointing to NULL, then nothing is leaked.

    Remember, addresses don't leak; objects leak.

    You can mitigate memory leaks by creating the objects on the stack (with straight MyClass t1;) and passing them around by reference rather than address; the object will then be deleted automatically when it passes out of scope. The main disadvantage of this comes when you have an object whose lifetime can't be coupled nicely to a particular scope. That's when you use pointers (or smart pointers, which hide most of the details at a cost of some restrictions). Really complex code is just better with garbage collection, though that has its own trade-offs (notably including being much more likely to increase memory consumption; this is the core reason why Java is known for being more memory hungry than C++).

Donal Fellows
Re point #2, a pointer in a structure points to NULL by default if the structure is itself directly defined at the global level. It's stuff on the stack or the heap that is arbitrary by default (unless a constructor does something about it, of course).
Donal Fellows