多调用构造函数将更改C ++中的成员指针地址

时间:2019-03-08 05:38:08

标签: c++ pointers construction

我编写了一个程序来检查类创建的初始化过程,发现多次调用构造函数会更改成员指针地址。看下面的代码片段。

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

输出为

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

似乎FF()的调用仅将ptr在其空间中初始化为NULL,并且调用后ptr变回到原始的0x400b40。

有人可以解释吗?

4 个答案:

答案 0 :(得分:3)

您对FF();的调用将创建一个新的未命名的基于FF的对象,构造它(生成您看到的输出),然后立即再次销毁它(对此您不显示任何内容)输出)。这就是ptr地址似乎变回原来的原因-因为它从未变过。添加一个析构函数,该析构函数打印出this的地址以查看这种情况。

顺便说一句,在第二个(参数化的)构造函数中使用this->ptr是未定义行为,因为您从未为ptr赋值。

如果您打算从参数化构造函数中调用默认构造函数,并且您的编译器支持C ++ 11,则可以delegate使用默认构造函数。

FF(const int* ptrcopy, const int valuecopy): FF() { /* ... */ }

答案 1 :(得分:0)

我认为这是在构造函数2中,您正在打印ptr(0x400b40)的未初始化值,然后使用FF()创建FF类型的新对象。然后将为新对象调用构造函数1,它的ptr成员将更改为NULL(因此在打印时它将为0)。新对象的构造函数完成后,它返回到构造函数2(调用了先前对象的析构函数),然后调用init,它将显示ptr的值与以前一样,因为该对象的ptr成员未更改。 / p>

这可能还会帮助您在析构函数中打印内容。那就是FF::~FF()

编辑:拼写和析构函数建议

答案 2 :(得分:0)

就像1201ProgramAlarm所说,做FF();不会 not 调用 current 对象的构造函数。为此,您可以执行以下操作(假设使用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

答案 3 :(得分:0)

比较以下内容:

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

};

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

您应该已经知道,您在函数末尾创建了一个超出范围的临时对象。您应该看到输出ctd

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

再次相同,只是有一点点不同:该对象在执行语句后立即超出范围,因此输出为cdt

现在,在构造函数中发生的情况完全相同,只需在构造函数的主体内调用FF()时创建一个临时的,单独的FF对象。

我想您打算使用构造函数委托(自C ++ 11起可用);但是,语法不同:

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

现在,在进入函数主体之前,将在this上调用默认构造函数。当然,只要适当地调用,就可以与 any 构造函数一起使用:

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

现在,默认构造函数将调用您的第二个构造函数。