0

I write a program to check the init process of class creation, and found calling the constructor multiple times changed the member pointer address. Look at following snippet.

#include <iostream>
using namespace std;

class FF {
public: 
    FF(){   
        this->ptr = NULL;
        value = 1;
        cout << "ptr address in 1: " << this->ptr <<endl;
    }

    FF(const int* ptrcopy, const int valuecopy){
        cout << "ptr address in 2: " << this->ptr << endl;
        FF();
        /* Is this equivalent with FF() ?
        this->ptr = NULL;
        value = 1;
        */
        init(ptrcopy, valuecopy);
    }

    void init(const int* ptrcopy, const int valuecopy) {
        cout << "ptr address in 3: " << this->ptr << endl;
        if (this->ptr != NULL)
        {
            cout << "error happened, the address of ptr is " << this->ptr << endl;
            return;
        }
    }

private:
        int* ptr;
        int  value;
};

int main(){
    int *ptr = new int(10);
    int value = 1;
    FF fclass(ptr, value);
    delete(ptr);
    return 0;
}

The output is

ptr address in 2: 0x400b40
ptr address in 1: 0
ptr address in 3: 0x400b40
error happened, the address of ptr is 0x400b40

It seems the calling of FF() only init the ptr to NULL in its space, and the ptr change back to original 0x400b40 after calling.

Can someone explain about it ?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Jiancong
  • 67
  • 1
  • 7
  • 4
    Off-topic: Prefer C++ keywords (`nullptr`) over old (obsolete) C macros (`NULL`). Prefer constructor's initialiser list (not to be confused with `std::initializer_list`) over in-body-inittialisation, i. e. `FF() : ptr(nullptr) { }` instead of `FF() { ptr = nullptr; }`; you avoid default initialisation + assignment in favour to directly initialising with parameters and in some cases (references, classes without default constructor, const objects) the initialiser list is the only way to construct/initialise the members. – Aconcagua Mar 08 '19 at 05:54

4 Answers4

3

Your call of FF(); will create a new, unnamed stack based FF object, construct it (generating the output you see), then immediately destroy it again (for which you don't show any output). This is why the ptr address seems to change back - because it never changed. Add in a destructor that prints out the address of this to see this occur.

Incidentally, your use of this->ptr in the second (parameterized) constructor is Undefined Behavior because you never assign a value to ptr.

If your intent is to call the default constructor from the parameterized constructor, and your compiler supports C++11, you can delegate to the default constructor.

FF(const int* ptrcopy, const int valuecopy): FF() { /* ... */ }
1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • 1
    Worth to mention constructor delegation (`FF(int const*, int) : FF() { /*...*/ }`)? Looks to me as if this is what she/he actually tries to do... – Aconcagua Mar 08 '19 at 05:59
0

I think what's happening is that in constructor 2 you are printing the uninitialized value for ptr (0x400b40) and then you are creating a new object of type FF with FF(). Then constructor 1 will be called for the new object, it's ptr member will be changed to NULL (so when printed it will be 0). After the constructor for the new object finishes it returns to constructor 2 (the destructor for the previously object is called) and then you call init which will display the same value for ptr as before since this object's ptr member hasn't been changed.

It might help you to also print the something in the destructor. That would be FF::~FF().

EDIT: Spelling and destructor suggestion

Keerpich
  • 343
  • 1
  • 10
0

Like 1201ProgramAlarm said, doing FF(); does not call the constructor of the current object. To do so, you would do something like below (assuming C++11):

class FF {
 public: 
  FF() : ptr(nullptr), value(1) {
    cout << "ptr address in 1: " << this->ptr <<endl;
  }
  FF(const int* ptrcopy, const int valuecopy) : FF() {
    cout << "ptr address in 2: " << this->ptr << endl;
    init(ptrcopy, valuecopy);
  }
  void init(const int* ptrcopy, const int valuecopy) {
    ...
  }
  ...
};

See also this question.

Edy
  • 462
  • 3
  • 9
0

Compare to the following:

class C
{
public:
    C() { std::cout << 'c' }
    ~C() { std::cout << 'd' }

};

void test()
{
    C f;
    std::cout << 't';
}

You should know about already, you create a temporary object running out of scope at the end of the function. You should see output ctd

void test()
{
    C();
    std::cout << 't';
}

Same again, with a little difference: The object runs out of scope right after the statement is executed, so output would be cdt.

Now exactly the same happens in your constructor, you just create a temporary, separate FF object when calling FF() inside the constructor's body.

I suppose you instead intended constructor delegation (available since C++11); however, syntax is different:

FF(int const*, int)
    : FF() // as if using the initialiser list
{ /* can do some extra work here */ }

Now, the default constructor will be called on this before entering the function body. Of course, works with any constructor, as long as called appropriately:

FF() : FF(nullptr, 0) { }

Now, the default constructor would call your second one.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59