Конструктор копирования C неправильно принимает аргумент

#c #copy-constructor

#c #конструктор копирования

Вопрос:

У меня есть следующий код, который ведет себя странно. Поток, который я понял до сих пор, display(line); будет вызывать конструктор копирования Line::Line(const Line amp;obj) , и ссылка line на будет передана. Однако cout<<"[origin] *ptr="<<*obj.ptr<<endl; будет печатать [origin] *ptr=32767 вместо [origin] *ptr=10 .

Более странно то, что если я раскомментирую // int x=3; , он будет печатать правильно, но я действительно понятия не имею, почему.

Исполняемый код можно найти по адресу: https://www.onlinegdb.com/pjbPO0X1f

 #include <iostream>
 
using namespace std;
 
class Line
{
   public:
      int getLength( void );
      Line( int len );
      Line( const Line amp;obj);

   private:
      int *ptr;
};
 
// constructor
Line::Line(int len)
{
    ptr=amp;len;
    cout<<"*ptr="<<(*ptr)<<endl;
}

// copy constructor
Line::Line(const Line amp;obj)
{
    // int x=3;
    cout<<"[origin] *ptr="<<*obj.ptr<<endl;
    ptr = new int;
    *ptr = *obj.ptr; // copy
}

int Line::getLength( void )
{
    return *ptr;
}
 
void display(Line obj)
{
   cout << "line=" << obj.getLength() <<endl;
}

int main( )
{
   Line line(10);
   display(line);
   return 0;
}
 

Комментарии:

1. Простой комментарий — не пишите код C таким образом. Зачем вводить указатели, когда в этом нет необходимости?

Ответ №1:

Ваша программа вызывает неопределенное поведение (UB). Когда ваш конструктор завершает:

 Line::Line(int len)
{
    ptr=amp;len;
    cout<<"*ptr="<<(*ptr)<<endl;
} // ptr is dangling
 

указатель ptr указывает на локальную переменную len , которая больше не существует. ptr теперь зависает, и любая попытка разыменования вызывает UB.

Ваша программа может делать все, что угодно. Вы также можете увидеть некоторые странные результаты, такие как добавление int x = 3 , в результате чего ваша программа «ведет себя правильно». Не беспокойтесь о том, почему это происходит, это просто результат UB.

Ответ №2:

Это распространенная ошибка (хотя это ее странная версия).

Этот код неверен

 // constructor
Line::Line(int len)
{
    ptr=amp;len;
    cout<<"*ptr="<<(*ptr)<<endl;
}
 

ptr создается для указания на len , но len является локальной переменной. Он уничтожается при выходе из конструктора. Это означает, что у вас есть указатель на объект, который больше не существует. Иногда это называется висячим указателем.

Затем позже в коде вы используете этот указатель

 cout<<"[origin] *ptr="<<*obj.ptr<<endl;
 

Поскольку указатель теперь недействителен, последствия непредсказуемы.

Одна из многих вещей, которые затрудняют указатели, заключается в том, что время жизни указателя и время жизни того, на что он указывает, вообще никак не связаны. Вы должны убедиться, что ваши указатели всегда указывают на объекты, которые все еще «живы».