views:

391

answers:

6

Hi, I'm relatively new to C++ and am having a hard trouble understanding the instantiation of object and pointers to objects.

Whats the difference between these two declaration in terms of memory and usage? :

MyClass obj1;
MyClass *obj2;

And also the specific problem I am having is that I have a class which has an unsigned short array where the last space of the array changes if I do this:

MyClass obj;
obj = MyClass("123");

MyClass has two constructors one which will take an int and as default will assign it to zero and splice it in parts of 3 digits or less. And another which will take a string representation of a number and do the same... hope that makes sense!

It works well if I declare it

MyClass obj = MyClass("123123123");

but not if I do it the other way. Why?

+3  A: 

When you say MyClass obj1; you create the object. MyClass * obj2; just saves space for the address of the object.

So MyClass obj1; does the following:

  • it sets up the name in the compiler symbol table
  • it allocates sizeof(MyClass) bytes of space — could be as big as you want
  • it runs the default ctor of MyClass, MyClass::MyClass() 9or a ctor that has all default arguments intead) putting the initialized object in the space it allocated
  • it remembers where that object is, associating it with the name 'obj1' in the symbol table.

while MyClass * obj2; instead

  • sets up the name obj2 in the symbol table
  • allocates space only for the address of a MyClass object, sizeof(MyClass*) — probably 4 or 8 bytes
  • doesn't run any constructor.

When you say MyClass obj; obj = MyClass("123123123") you

  • create and allocate a MyClass object for obj using the default ctor
  • create and allocate another MyClass object
  • assign that new MyClass object to replace the old one.
Charlie Martin
that's possibly the best explanation i've ever read
cbrulak
Neil, could you be more specific? I can't find anything wrong either. (Did you perhaps misread `MyClass obj; obj = MyClass("123123123")` for `MyClass obj = MyClass("123123123")`?)
avakar
Whups, I take it back, I read the third point in the answer wromg (might be a good idea to format code as code, not text). My apologies to all.
anon
in a nutshell, his obj = MyClass("123123123"); both copies and assigns (copy-assignment operator) :)
Johannes Schaub - litb
Two C topics I never get involved in arguments about - lvalues and multi-dimensional arrays :-)
anon
On your other point, this guys obviously pretty new; I thin the way I said it was clearer.
Charlie Martin
+2  A: 

When you call

MyClass obj = MyClass("123123123");

You are actually creating two objects! The correct way is to call

MyClass obj("123123123");
R Caloca
Wrong, nearly all compilers optimize it to the second form even with optimizations turned off.
tstenner
Correct way is not strictly the best terminology. Most people would do it the second way but the first is valid under most situations and the compiler is allowed to optimize away the second object.
Martin York
Agreed that most if not all compilers will fix it, but IMHO it is 'conceptually' wrong since in theory you are calling the temp object's constructor and then the copy constructor of the 'obj' instance.
R Caloca
also, the copy constructor must be available, no matter what. So you couldn't make MyClass non-copyable if you want to stick with way 1 of initialization.
Johannes Schaub - litb
A: 

In the first code, one actually creates the object of type MyClass so it consumes as much space as needed. the other one just defines a pointer, so you reserve as much space as you would need for an addresss on your system (typically 4 bytes, sometimes 8)

When you split your initialization into two lines, you are first creating MyClass with a default constructor, then creating a MyClass with a parameterized constructor, and then using the assignment operator to override the contents of the first with the contents of the second. This is wasteful. Because constructors can have side effects, the compiler would probably not optimize this for you.

In the third piece of code you provided, you are actually using a single constructor that takes a parameter. Not assignment takes place.

Uri
+8  A: 

The difference:

MyClass  obj1;
MyClass *obj2;

Here obj1 is an instance of MyClass.
While obj2 can potentially hold the address of an instance of MyClass.

Also obj1 will automatically be initialized by the constructors, while obj2 is not initialized by default (and thus points to random memory). Once initialized obj2 may take the special value NULL which indicates that it is not pointing at an object.

obj2 = &obj1;

Here we initialize obj2 to point at the address in memory of obj1. If you change any of the members of obj1 then you can see the changes by looking at them through obj2 (but because obj2 is a pointer you need to de-reference).

obj1.plop = 5;

std::cout << obj1.plop << "\n";
std::cout << obj2->plop << "\n";  Should print the same values.

The following is actually two different things:

MyClass obj;
obj = MyClass("123");
  • Line one initializes 'obj' with the default constructor.
  • Line two: creates a temporary object constructed with the string "123". Once this temporary object is created it is copied onto 'obj' using the assignment operator. If you did not define an assignment operator the compiler will have generated one for you. If your class contains pointers then the default version will probably not work correctly (in most other situations the default assignment operator should work fine).

This line probably works:

MyClass obj = MyClass("123123123");

Because the compiler has optimised this into:

MyClass obj("123123123");
Martin York
In `obj=MyClass("123")`, it is the assignment operator that's called, not the copy-constructor.
avakar
@avakar: Corrected.
Martin York
A: 

The difference between

MyClass obj1;
MyClass *obj2;

Is the first creates an object (size = size of the object), whereas the second only creates a pointer to an object (4 bytes on 32 bit systems) but not the actual object. In order to do that you'd need to do

MyClass* obj2 = new MyClass("123");

This would allocate 4 bytes for the pointer and the x bytes where x is the size of the object. If you manually "new" something like this, then you are responsible for manually destroying it later using "delete".

The MyClass obj1 will be "destroyed" when it goes out of scope.

Colin Desmond
Heap allocation is not necessary though. You can also say "MyClass* obj2 = " and then let the object get destroyed when it goes out of scope (ie - no need for "delete").
Tom
A: 

Two things are affected by these declarations: the lifetime of the variable, and where the memory is allocated.

The pointer version MyClass* is declaring a variable that points at an instance of MyClass. It does not itself allocate it; the allocation from the 'free store' (which is always the same as the 'heap') occurs when you explicitly 'new' it, and is freed when you 'delete' it.

The following code works:

MyClass* test_works() {
  MyClass* obj = new MyClass;
  return obj;
}

The non-pointer version is allocating the memory in the context it is specified - the declaration might be at a global level, or on the stack in a function, or as a member of another object ('composition') - and it is automatically allocated and freed as it comes in and out of scope.

The following code, for example, will fail:

MyClass* test_crashes() {
  MyClass obj;
  return &obj;
}
Will