Вопрос о поверхностном копировании в C++

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
1 550
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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

Ответ принят как подходящий

В продолжение того, что сказал @ [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;
};

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

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

Ваш оператор присваивания не безопасен для исключений. См. Недавний вопрос о безопасности копирования и исключений: stackoverflow.com/questions/214891/…

Luc Hermitte 19.10.2008 12:29

Дох, хорошо, я исправил это. Вы понимаете, что я имею в виду, говоря, что это боль и трудно понять, тогда да

1800 INFORMATION 19.10.2008 12:53

Лучший способ сделать конструктор копирования и operator = private - наследовать от boost :: noncopyable. Вы должны сделать это для каждого отдельного класса, если не знаете наверняка, что его можно скопировать.

CesarB 19.10.2008 19:17

С идиомой копирования и обмена действительно легко сделать это правильно (даже если это немного неэффективно)

Luc Hermitte 20.10.2008 00:49

Другие вопросы по теме