Вопрос о мелкой копии в C ++ - PullRequest
5 голосов
/ 19 октября 2008

Скажем, у меня есть структура "s" с переменной члена указателя int "i". Я выделяю память в куче для i в конструкторе по умолчанию s. Позже в другой части кода я передаю экземпляр s по значению некоторой функции. Я делаю мелкую копию здесь? Предположим, я не реализовал никаких конструкторов копирования или операторов присваивания или чего-либо для s ... просто конструктор по умолчанию.

Ответы [ 3 ]

8 голосов
/ 19 октября 2008

Чтобы прокомментировать сказанное @ [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;
  }
};

Чтобы решить эту проблему, есть несколько методов.

Всегда реализуйте конструктор копирования и оператор = в классах, которые используют необработанные указатели памяти.

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;
};

Само собой разумеется, это большая боль, и есть много тонкостей, чтобы понять правильно. Я даже не совсем уверен, что сделал это прямо здесь, и я делал это несколько раз. Не забывайте, что вам нужно скопировать всех участников - если вы добавите новые позже, не забудьте добавить их тоже!

Сделайте конструктор копирования и оператор = 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)
  {
  }
};
5 голосов
/ 19 октября 2008

Да, это мелкая копия. Теперь у вас есть две копии s (одна в вызывающем, одна в стеке в качестве параметра), каждая из которых содержит указатель на тот же блок памяти.

2 голосов
/ 19 октября 2008

У вас будет две копии структуры s, каждая из которых будет иметь свой собственный указатель i, но оба указателя i будут иметь одинаковое значение, указывающее на один и тот же адрес в памяти - так что да, это будет мелкой копией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...