Копировать конструктор с указателями
Недавно я обнаружил, что когда у меня есть указатели внутри класса, мне нужно указать конструктор Copy.
Чтобы узнать, что я сделал следующий простой код. Он компилируется, но дает мне ошибку выполнения при выполнении конструктора копирования.
Я пытаюсь скопировать только значение из указателя скопированного объекта, но избегая назначения того же адреса.
Итак, что здесь не так?
class TRY{
public:
TRY();
~TRY();
TRY(TRY const &);
int *pointer;
void setPointer(int);
};
void TRY::setPointer(int a){
*pointer = a;
return;
}
TRY::TRY(){}
TRY::~TRY(){}
TRY::TRY(TRY const & copyTRY){
int a = *copyTRY.pointer;
*pointer = a;
}
int main(){
TRY a;
a.setPointer(5);
TRY b = a;
b.setPointer(8);
cout << "Address of object a = " << &a << endl;
cout << "Address of object b = " << &b << endl;
cout << "Address of a.pointer = " << a.pointer << endl;
cout << "Address of b.pointer = " << b.pointer << endl;
cout << "Value in a.pointer = " << *a.pointer << endl;
cout << "Value in b.pointer = " << *b.pointer << endl;
return 0;
}
Я буду использовать эту концепцию для других классов с большим количеством указателей в ней, где мне нужно скопировать все значения с объекта на другой. Копирование первоначально необходимо для этого кода, поэтому я хотел бы сохранить возможность копирования (я не буду скрывать конструктор копирования как закрытый).
Кроме того, реальный класс, который мне нужно реализовать, имеет 10 указателей, и он может меняться со временем. Разве нет более умного способа иметь конструктор глубоких копий на С++?...
Ответы
Ответ 1
С помощью инструкции int* pointer
вы только что указали указатель, но не выделили какую-либо память. Сначала вы должны указать на правильное расположение памяти, выделив некоторую память следующим образом: int* pointer = new int
. Затем в конструкторе копирования вы должны выделить память для скопированного объекта. Кроме того, не забудьте освободить память, используя delete в деструкторе.
Надеюсь, этот пример поможет:
class B
{
public:
B();
B(const B& b);
~B();
void setVal(int val);
private:
int* m_p;
};
B::B()
{
//Allocate the memory to hold an int
m_p = new int;
*m_p = 0;
}
B::B(const B& b)
{
//Allocate the memory first
m_p = new int;
//Then copy the value from the passed object
*m_p = *b.m_p;
}
B::~B()
{
//Release the memory allocated
delete m_p;
m_p = NULL;
}
void B::setVal(int val)
{
*m_p = val;
}
Ответ 2
Недавно я обнаружил, что когда я иметь указатели внутри класса, мне нужно для указания конструктора копирования.
Это не совсем так. Когда у вас есть указатели в вашем классе и выделяете память с помощью new
, вам придется беспокоиться о конструкторе копирования. Кроме того, не забудьте оператор присваивания и деструктор.
Вы должны удалить выделенную память, используя delete
.
Он назвал Закон Большой тройки.
Пример:
~Matrix(); //Destructor
Matrix(const Matrix& m); //Copy constructor
Matrix& operator= (const Matrix& m); //Assignment operator
Ответ 3
Если вы хотите сделать глубокую копию, вы, конечно же, должны также выделить новую память для хранения значений. Если у оригинала есть указатель на int, и вы не хотите, чтобы копия использовала одно и то же значение указателя, вы должны выделить новую память для хранения int и затем скопировать туда значение.
Ваш пример не очень ясен, он не показывает реализацию вашего конструктора копирования или как инициализируется член pointer
.
Ответ 4
если он имеет указатель на обычный тип, то
A::A(const A& a):
pointer_( new int( *a.pointer_ ) )
{
}
если он имеет указатель на некоторый базовый класс, то
A::A(const &a ):
pointer_( a.pointer_->clone() )
{
}
Клонирование - это реализация шаблона прототипа
Не забудьте удалить указатель в деструкторе
A::~A()
{
delete pointer_;
}
Чтобы исправить ваш пример
TRY::TRY(TRY const & copyTRY){
int a = *copyTRY.pointer;
pointer = new int(a);
}
Ответ 5
Ваша проблема в этой строке прямо здесь:
*pointer = a;
Все, что обычно происходит в вашем конструкторе по умолчанию, еще не произошло, включая выделение памяти для *pointer
.
Исправление состоит в том, чтобы выделить память для целого числа. Вы можете использовать malloc
и друзей или new
для этого, но убедитесь, что это тот же метод, который вы используете в своем конструкторе по умолчанию, потому что вы получаете только один деструктор, а вызовы должны совпадать.
Ответ 6
Если членская (мелкая) копия в порядке, то вам не нужно ничего делать. Если вам нужна глубокая копия, вам необходимо выделить новое хранилище для копий всех членов.
Ответ 7
Недавно я обнаружил, что когда я иметь указатели внутри класса, мне нужно для указания конструктора копирования
Чаще всего это хорошая идея просто отключить его, объявив его (и оператор-ассистент) частным и не реализуя его.
Ответ 8
При написании Copy Constructor вы должны выделить память для всех членов.
В вашем случае:
TRY::TRY(TRY const & copyTRY){
pointer = new int(*(copyTry.pointer));
}
Оператор = как-то подобен, но без выделения памяти.
TRY& operator=(TRY const& otherTRY){
this->a = *(otherTry.pointer)
return *this
}
Ответ 9
Чаще всего, если вам нужно написать конструктор копирования или оператор присваивания, вы делаете что-то неправильно. Оставьте конструкторы копирования и операторы присваивания исполнителям стандартной библиотеки. Составьте свои классы уже скопируемых и присваиваемых элементов, и вам не придется писать свои собственные.
Например, возможно, что int * member должен быть std::vector.
Если вы не можете сделать класс по умолчанию скопированным/назначаемым, возможно, вы можете сделать его не копируемым/назначаемым, объявив, но не реализуя, частный конструктор копирования и оператор присваивания.
Только если ни одно из вышеперечисленных вариантов не является выполнимым, если вы реализуете свой собственный конструктор копий или оператор присваивания.