Страница 3 из 4

Re: Занимательная задачка: понимание deep copy

Добавлено: 30 ноя 2015, 15:54
Din666
Да возможно умный указатель любого типа и излишен. Однако в данном случае надо внимательно посмотреть на std/boost ::shared_ptr, там есть перегруженный operator bool().
и обращение к данным контролируется void copy() ....... if ( rhs.m_pHuge )

Re: Занимательная задачка: понимание deep copy

Добавлено: 30 ноя 2015, 18:12
Absurd
Если честно, то и unique_ptr тоже не особо нужен, так как у нас есть полный контроль за конструктором и деструктором CWorker.
Ну не знаю, если в Visual C++, gcc или clang включить генерацию asm листингов в режиме Release компиляции и поизучать их немного, то можно увидеть что operator* и operator-> они инлайнят чисто и никакого оверхеда не создают. При этом от всех возможных неприятных кейсов связанных с исключениями в конструкторах unique_ptr/make_unique защищают.

Re: Занимательная задачка: понимание deep copy

Добавлено: 01 дек 2015, 16:38
Romeo
Din666 писал(а):и обращение к данным контролируется void copy() ....... if ( rhs.m_pHuge )
У этого if нет else.

Смотри, вот пример:

Код: Выделить всё

CWorker w1;
w1.Process();

CWorker w2;
w1 = w2;
Так как w2 внутри содержит nullptr, то после присваивания в w1 тоже должен быть nullptr, а по факту у нас там остаётся указатель на экземпляр CHuge.

Re: Занимательная задачка: понимание deep copy

Добавлено: 01 дек 2015, 16:47
Romeo
Absurd писал(а):Ну не знаю, если в Visual C++, gcc или clang включить генерацию asm листингов в режиме Release компиляции и поизучать их немного, то можно увидеть что operator* и operator-> они инлайнят чисто и никакого оверхеда не создают. При этом от всех возможных неприятных кейсов связанных с исключениями в конструкторах unique_ptr/make_unique защищают.
Я не говорю, что использование std::unique_ptr излишне. Оно здесь более, чем приемлемо. Но можно и не "заморачиваться", так как, на самом деле, тело конструктора настолько тривиально, что при всём желании в нём не добьёшься partial initialization, от которого нас бы спас умный поинтер :)

А вот использование std::shared_ptr действительно будет кривоватым. Контекст применение не тот, как следствие есть ненужный оверхед.

Re: Занимательная задачка: понимание deep copy

Добавлено: 01 дек 2015, 18:07
Din666
Romeo писал(а):У этого if нет else.
ота фак же, точно ))))) else m_pHuge.reset (); )))))))

Re: Занимательная задачка: понимание deep copy

Добавлено: 01 дек 2015, 20:19
Romeo
Совершенно верно. Итого, вот честный вариант:

Код: Выделить всё

class CWorker
{
public:
   CWorker() = default;

   CWorker(const CWorker& rhs)
   {
      assign(rhs);
   }

   CWorker & operator=(const CWorker& rhs)
   {
      if (this != &rhs)
      {
         assign(rhs);
      }
      return *this;
   }

   void Process()
   {
      if (!m_pHuge)
      {
         m_pHuge.reset(new CHuge);
      }
      m_pHuge->DoAction();
   }

private:
   inline void assign(const CWorker& rhs)
   {
      m_pHuge.reset(rhs.m_pHuge ? new CHuge(rhs.m_pHuge.get()) : nullptr); 
   }

   std::unique_ptr<CHuge> m_pHuge;
};

Re: Занимательная задачка: понимание deep copy

Добавлено: 02 дек 2015, 09:45
Din666
и таки все равно неправильно )))

если принять что ифейс CHuge скорее всего такой: struct CHuge {void DoAction(){}};

no matching function for call to ‘CHuge::CHuge(std::unique_ptr<CHuge>: :p ointer)’
m_pHuge.reset(rhs.m_pHuge ? new CHuge(rhs.m_pHuge.get()) : nullptr);
note: candidate expects 0 arguments, 1 provided
note: constexpr CHuge::CHuge(const CHuge&)
note: no known conversion for argument 1 from ‘std::unique_ptr<CHuge>: :p ointer {aka CHuge*}’ to ‘const CHuge&’
note: constexpr CHuge::CHuge(CHuge&&)
note: no known conversion for argument 1 from ‘std::unique_ptr<CHuge>: :p ointer {aka CHuge*}’ to ‘CHuge&&’

надо m_pHuge.reset(rhs.m_pHuge ? new CHuge(*rhs.m_pHuge) : nullptr);

и почему в конструкторе копирования отсутствует проверка selfcopy, а если CWorker worker1(worker1); - не знаю наскока это глупо - но собирается )))))

Re: Занимательная задачка: понимание deep copy

Добавлено: 02 дек 2015, 17:03
Romeo
Извиняюсь, отправил не скомпилив, так как по графику должны были вот-вот отключить свет. Я ведь из Крыма. Действительно закралась ошибка (забыл разыменование). Теперь она исправлена.

По поводу проверки селфкопи в конструкторе копирования скажу, что обычно она в нём не делается, так как нужно быть очень глупым программистом, чтобы написать указанную строку. Ко всему прочему, большинство компиляторов её попросту не скомпилируют, так как мы пытаемся инициализовать объект самим собой, то есть ещё неинициализиваронным объектом.

Код: Выделить всё

#include <memory>

/* testing data section begin */

class CHuge
{
public:
   void DoAction(){}
};

const_expr bool g_bSomeCondition1 = true;
const_expr bool g_bSomeCondition2 = true;
const_expr bool g_bSomeCondition3 = true;

/* testing data section end */

class CWorker
{
public:
   CWorker() = default;

   CWorker(const CWorker& rhs)
   {
      assign(rhs);
   }

   CWorker& operator=(const CWorker& rhs)
   {
      if (this != &rhs)
      {
         assign(rhs);
      }
      return *this;
   }

   void Process()
   {
      if (!m_pHuge)
      {
         m_pHuge.reset(new CHuge);
      }
      m_pHuge->DoAction();
   }

private:
   inline void assign(const CWorker& rhs)
   {
      m_pHuge.reset(rhs.m_pHuge ? new CHuge(*rhs.m_pHuge) : nullptr); 
   }

   std::unique_ptr<CHuge> m_pHuge;
};

int main()
{
   CWorker worker1;
   if (g_bSomeCondition1)
   {
      worker1.Process();
   }

   CWorker worker2;
   if (g_bSomeCondition2)
   {
      worker2 = worker1;
   }

   if (g_bSomeCondition3)
   {
      worker1.Process();      
      worker2.Process();
   }

   return 0;
}

Re: Занимательная задачка: понимание deep copy

Добавлено: 02 дек 2015, 17:39
Din666
ok. осталась последняя мелочь и код станет идеальным )). А зачем делать лишний вызов метода get() ...... *rhs.m_pHuge.get(), если можно просто *rhs.m_pHuge разименовать.
А какже: 'не надо умных указателей, надо все вручную писать, если мы "имеем полный контроль"' ? ))

Re: Занимательная задачка: понимание deep copy

Добавлено: 02 дек 2015, 22:07
Romeo
По этому поводу я уже писал выше. Я был резко против лишь shared_ptr, а против unique_ptr ничего не имел против :)

Написать на сырых поинтерах можно. Более того, это было бы даже более поучительно, чем использовать unique_ptr, ведь задача больше обучающая, чем реальная... Но стало лень после того, как понял, что по-хорошему помимо конструктора, деструктора, придётся заимплементить ещё и move-конструктор (в main он не используется, но для полной картинки необходим).