Вопрос о неглубоком копировании в C ++
-
03-07-2019 - |
Вопрос
Допустим, у меня есть структура "s" с переменной-членом указателя int "i".Я выделяю память в куче для i в конструкторе s по умолчанию.Позже, в какой-то другой части кода, я передаю экземпляр s по значению некоторой функции.Я что, делаю здесь поверхностную копию?Предположим, я не реализовывал никаких конструкторов копирования, операторов присваивания или чего-либо еще для s...просто конструктор по умолчанию.
Решение
В продолжение того, что @[don.neufeld.myopenid.com] сказал: это не только мелкую копию, но это либо (выбрать) утечка памяти или оборванных указатель.
// memory leak (note that the pointer is never deleted)
class A
{
B *_b;
public:
A()
: _b(new B)
{
}
};
// dangling ptr (who deletes the instance?)
class A
{
B *_b;
public:
A()
... (same as above)
~A()
{
delete _b;
}
};
Чтобы решить эту проблему, существует несколько методов.
Всегда реализуйте конструктор копирования и operator= в классах, которые используют необработанные указатели на память.
class A
{
B *_b;
public:
A()
... (same as above)
~A()
...
A(const A &rhs)
: _b(new B(rhs._b))
{
}
A &operator=(const A &rhs)
{
B *b=new B(rhs._b);
delete _b;
_b=b;
return *this;
};
Излишне говорить, что это серьезная проблема, и есть немало тонкостей, с которыми нужно разобраться.Я даже не совсем уверен, что сделал это прямо здесь, хотя делал это несколько раз.Не забывайте, что вам нужно скопировать всех участников - если позже вы добавите несколько новых, не забудьте добавить и их!
Сделайте конструктор копирования и operator= private в вашем классе. Это и есть решение "запереть дверь".Это просто и эффективно, но иногда чрезмерно защитно.
class A : public boost::noncopyable
{
...
};
Никогда не используйте необработанные указатели. Это просто и эффективно.Здесь есть много вариантов:
- Используйте строковые классы вместо необработанных указателей на символы
- Используйте std:: auto_ptr, boost:: shared_ptr, boost:: scoped_ptr и т. Д
Пример:
// uses shared_ptr - note that you don't need a copy constructor or op= -
// shared_ptr uses reference counting so the _b instance is shared and only
// deleted when the last reference is gone - admire the simplicity!
// it is almost exactly the same as the "memory leak" version, but there is no leak
class A
{
boost::shared_ptr<B> _b;
public:
A()
: _b(new B)
{
}
};
Другие советы
Да, это мелкая копия. Теперь у вас есть две копии s (одна в вызывающем, одна в стеке в качестве параметра), каждая из которых содержит указатель на тот же блок памяти.
У вас будет две копии структуры s
, у каждой из которых будет свой указатель i
, но оба указателя i
будут иметь одно и то же значение, указывающее на один и тот же адрес в памяти - так что да, это будет мелкая копия.