#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;
Поскольку указатель теперь недействителен, последствия непредсказуемы.
Одна из многих вещей, которые затрудняют указатели, заключается в том, что время жизни указателя и время жизни того, на что он указывает, вообще никак не связаны. Вы должны убедиться, что ваши указатели всегда указывают на объекты, которые все еще «живы».