Конструктор с несколькими вызовами изменит адрес указателя на член в C ++ - PullRequest
0 голосов
/ 08 марта 2019

Я пишу программу для проверки процесса инициализации процесса создания класса и обнаружил, что вызов конструктора несколько раз менял адрес указателя члена. Посмотрите на следующий фрагмент.

#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 ]

3 голосов
/ 08 марта 2019

Ваш вызов FF(); создаст новый безымянный стек на основе FF объекта, создаст его (генерирует вывод, который вы видите), а затем немедленно уничтожит его снова (для которого вы не показываете никакого вывода). Вот почему адрес ptr, кажется, возвращается обратно - потому что он никогда не менялся. Добавьте деструктор, который печатает адрес this, чтобы увидеть, как это происходит.

Кстати, вы используете this->ptr во втором (параметризованном) конструкторе как Undefined Behavior, потому что вы никогда не присваиваете значение ptr.

Если вы намереваетесь вызвать конструктор по умолчанию из параметризованного конструктора, и ваш компилятор поддерживает C ++ 11, вы можете делегировать конструктору по умолчанию.

FF(const int* ptrcopy, const int valuecopy): FF() { /* ... */ }
0 голосов
/ 08 марта 2019

Сравните со следующим:

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) { }

Теперь конструктор по умолчанию будет вызывать ваш второй.

0 голосов
/ 08 марта 2019

Как сказал 1201ProgramAlarm, выполнение FF(); делает не вызовом конструктора 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) {
    ...
  }
  ...
};

См. Также этот вопрос .

0 голосов
/ 08 марта 2019

Я думаю, что в конструкторе 2 вы печатаете неинициализированное значение ptr (0x400b40), а затем создаете новый объект типа FF с FF(). Тогда конструктор 1 будет вызван для нового объекта, его член ptr будет изменен на NULL (поэтому при печати он будет равен 0). После завершения конструктора для нового объекта он возвращается к конструктору 2 (вызывается деструктор для ранее созданного объекта), а затем вызывается init, который отображает то же значение для ptr, что и раньше, поскольку член ptr этого объекта не был изменен.

Это может также помочь вам напечатать что-то в деструкторе. Это было бы FF::~FF().

РЕДАКТИРОВАТЬ: орфография и предложение деструктора

...