0

I have the following class definition in C++ :

class foo {
private:
   int      a,b,c;

   foo();     // constructor
   void     setup(int x, int y);
   void     some_function_that_changes_a_b_c();
}


foo::foo() {
   a = b = c = 0;
}

void foo::setup(int x, int y) {
    foo();    // <-- I use this to make sure a,b,c are initialized
    a = x;
    b = y;    // <-- c is left unchanged!
}

void foo::some_function_that_changes_a_b_c() {
    // here's some code that changes variables a,b,c
}

And then I have a code that uses this class:

foo  *a = new foo;
a->setup(1,2);
a->some_function_that_changes_a_b_c();
a->setup(5,7);   // <-- HERE IS THE PROBLEM

The problem is that on the second call to setup(), it doesnt run the foo() constructor to reset my values or a,b,c , so the c variable stays with the old value it was on the call to some_function_that_changes_a_b_c(), I tested this with the debugger and it seems like on the second call, foo() is addressing a different memory space for the variables.

Is there a way to fix this?

Miki Berkovich
  • 467
  • 5
  • 16
  • **Books:** https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Galik Jan 07 '15 at 16:59
  • you should use a function to initialize the properties instead of directly doing it in the constructor – Hacketo Jan 07 '15 at 16:59
  • This has already been addressed here - http://stackoverflow.com/questions/14402097/calling-class-constructor-in-member-function-c-solved – sn710 Jan 07 '15 at 17:14

4 Answers4

4

In C++, constructor is only called once when the object is constructed, and not anymore in your class method. In your code

void foo::setup(int x, int y) {
    foo();  // ==> this line
}

A temporary foo object will be created, which is independent of the current this object, and therefore the a, b and c fields of this object will be unchanged.

In order to do what you have in mind, create a class method, say foo::reset(), and call it from inside foo::setup().

Ying Xiong
  • 4,578
  • 8
  • 33
  • 69
1

You should not call your constructor after the object has been created. Put the functionality into a protected reset() function that is called from both your constructor and the setup function.

Background: Your call to foo() in setup does not reinitialize the object, but create a second local object that is never used. In general, you should refrain from explicitly calling constructors unless you absolutely know what you're doing.

Daerst
  • 954
  • 7
  • 24
1
foo();    // <-- I use this to make sure a,b,c are initialized

Unfortunately, it doesn't do that. It creates and destroys a temporary object. You can't call a constructor directly; they are only used to initialise objects at the start of their lifetime.

You could reassign your object with a freshly initialised one:

*this = foo();

or you could move the body of the constructor into a reset function, and call that whenever you want to restore the initial state.

My preferred option would be use separate objects rather than trying to reuse a modified one, and to perform all the "setup" when initialising each object:

foo a(1,2);
a.some_function_that_changes_a_b_c();
foo b(5,7);  // known to be in a freshly initialised state
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

What you are attempting to do is two-stage initialization. This is unnecessary and clumsy in C++. You need to realize two things

  1. The constructor is called at the point of object creation

  2. If you have an object to say f.setup(1, 2, 3); on, that means the constructor must have run already.

now:

foo f; // calls foo() with f
f.setup(1, 2, 3); // foo() has arleady been called

as Ying Xiong has pointed out, the foo() line creates a temporary object unrelated to the this you are working with.

Rather than two stage initialization (constructor, then initializer) you can have your constructor take variables and do the initialization

class foo {
  private:
   int      a,b,c;
  public:
   foo(int x, int y, int z);     // constructor
};

foo::foo(int x, int y, int z)
   : a(x),
   b(y),
   c(z)
{ }

and then instead construct with the values you want

foo f(1, 2, 3);

if you need to "reset" the values each time setup is called, then you're best to use a reset function, or similar. Trying to call a constructor on yourself is possible but not very healthy.

void foo::reset() {
    a = b = c = 0;
}
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174