0

我写了一个程序检查类创建的init过程,发现多次调用构造函数改变了成员指针地址。看下面的片段。

#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

4 回答 4

3

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

顺便说一句,您this->ptr在第二个(参数化)构造函数中使用的是 Undefined Behavior,因为您从未为ptr.

如果您的意图是从参数化构造函数调用默认构造函数,并且您的编译器支持 C++11,则可以委托给默认构造函数。

FF(const int* ptrcopy, const int valuecopy): FF() { /* ... */ }
于 2019-03-08T05:45:11.733 回答
0

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

它可能会帮助您在析构函数中打印一些东西。那将是FF::~FF()

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

于 2019-03-08T05:50:40.993 回答
0

就像1201ProgramAlarm说的,doingFF();调用当前对象的构造函数。为此,您将执行以下操作(假设 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) {
    ...
  }
  ...
};

另请参阅此问题

于 2019-03-08T06:01:38.550 回答
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在进入函数体之前被调用。当然,只要调用得当,就可以与任何构造函数一起使用:

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

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

于 2019-03-08T06:12:02.197 回答