Juan Besa
Juan Besa

Reputation: 4410

C++ Problem initializing an object twice

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?

Upvotes: 2

Views: 2685

Answers (6)

Loki Astari
Loki Astari

Reputation: 264441

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");

Upvotes: 8

Charlie Martin
Charlie Martin

Reputation: 112366

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.

Upvotes: 3

Will
Will

Reputation: 75635

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;
}

Upvotes: 0

Colin Desmond
Colin Desmond

Reputation: 4854

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.

Upvotes: 0

Uri
Uri

Reputation: 89749

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.

Upvotes: 0

R Caloca
R Caloca

Reputation: 59

When you call

MyClass obj = MyClass("123123123");

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

MyClass obj("123123123");

Upvotes: 2

Related Questions