Занимательная задачка: понимание deep copy
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
Да возможно умный указатель любого типа и излишен. Однако в данном случае надо внимательно посмотреть на std/boost ::shared_ptr, там есть перегруженный operator bool().
и обращение к данным контролируется void copy() ....... if ( rhs.m_pHuge )
и обращение к данным контролируется void copy() ....... if ( rhs.m_pHuge )
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Ну не знаю, если в Visual C++, gcc или clang включить генерацию asm листингов в режиме Release компиляции и поизучать их немного, то можно увидеть что operator* и operator-> они инлайнят чисто и никакого оверхеда не создают. При этом от всех возможных неприятных кейсов связанных с исключениями в конструкторах unique_ptr/make_unique защищают.Если честно, то и unique_ptr тоже не особо нужен, так как у нас есть полный контроль за конструктором и деструктором CWorker.
2B OR NOT(2B) = FF
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
У этого if нет else.Din666 писал(а):и обращение к данным контролируется void copy() ....... if ( rhs.m_pHuge )
Смотри, вот пример:
Код: Выделить всё
CWorker w1;
w1.Process();
CWorker w2;
w1 = w2;
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Я не говорю, что использование std::unique_ptr излишне. Оно здесь более, чем приемлемо. Но можно и не "заморачиваться", так как, на самом деле, тело конструктора настолько тривиально, что при всём желании в нём не добьёшься partial initialization, от которого нас бы спас умный поинтерAbsurd писал(а):Ну не знаю, если в Visual C++, gcc или clang включить генерацию asm листингов в режиме Release компиляции и поизучать их немного, то можно увидеть что operator* и operator-> они инлайнят чисто и никакого оверхеда не создают. При этом от всех возможных неприятных кейсов связанных с исключениями в конструкторах unique_ptr/make_unique защищают.

А вот использование std::shared_ptr действительно будет кривоватым. Контекст применение не тот, как следствие есть ненужный оверхед.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
ота фак же, точно ))))) else m_pHuge.reset (); )))))))Romeo писал(а):У этого if нет else.
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Совершенно верно. Итого, вот честный вариант:
Код: Выделить всё
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;
};
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
и таки все равно неправильно )))
если принять что ифейс CHuge скорее всего такой: struct CHuge {void DoAction(){}};
no matching function for call to ‘CHuge::CHuge(std::unique_ptr<CHuge>:
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>:
ointer {aka CHuge*}’ to ‘const CHuge&’
note: constexpr CHuge::CHuge(CHuge&&)
note: no known conversion for argument 1 from ‘std::unique_ptr<CHuge>:
ointer {aka CHuge*}’ to ‘CHuge&&’
надо m_pHuge.reset(rhs.m_pHuge ? new CHuge(*rhs.m_pHuge) : nullptr);
и почему в конструкторе копирования отсутствует проверка selfcopy, а если CWorker worker1(worker1); - не знаю наскока это глупо - но собирается )))))
если принять что ифейс CHuge скорее всего такой: struct CHuge {void DoAction(){}};
no matching function for call to ‘CHuge::CHuge(std::unique_ptr<CHuge>:

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>:

note: constexpr CHuge::CHuge(CHuge&&)
note: no known conversion for argument 1 from ‘std::unique_ptr<CHuge>:

надо m_pHuge.reset(rhs.m_pHuge ? new CHuge(*rhs.m_pHuge) : nullptr);
и почему в конструкторе копирования отсутствует проверка selfcopy, а если CWorker worker1(worker1); - не знаю наскока это глупо - но собирается )))))
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Извиняюсь, отправил не скомпилив, так как по графику должны были вот-вот отключить свет. Я ведь из Крыма. Действительно закралась ошибка (забыл разыменование). Теперь она исправлена.
По поводу проверки селфкопи в конструкторе копирования скажу, что обычно она в нём не делается, так как нужно быть очень глупым программистом, чтобы написать указанную строку. Ко всему прочему, большинство компиляторов её попросту не скомпилируют, так как мы пытаемся инициализовать объект самим собой, то есть ещё неинициализиваронным объектом.
По поводу проверки селфкопи в конструкторе копирования скажу, что обычно она в нём не делается, так как нужно быть очень глупым программистом, чтобы написать указанную строку. Ко всему прочему, большинство компиляторов её попросту не скомпилируют, так как мы пытаемся инициализовать объект самим собой, то есть ещё неинициализиваронным объектом.
Код: Выделить всё
#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;
}
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
ok. осталась последняя мелочь и код станет идеальным )). А зачем делать лишний вызов метода get() ...... *rhs.m_pHuge.get(), если можно просто *rhs.m_pHuge разименовать.
А какже: 'не надо умных указателей, надо все вручную писать, если мы "имеем полный контроль"' ? ))
А какже: 'не надо умных указателей, надо все вручную писать, если мы "имеем полный контроль"' ? ))
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
По этому поводу я уже писал выше. Я был резко против лишь shared_ptr, а против unique_ptr ничего не имел против 
Написать на сырых поинтерах можно. Более того, это было бы даже более поучительно, чем использовать unique_ptr, ведь задача больше обучающая, чем реальная... Но стало лень после того, как понял, что по-хорошему помимо конструктора, деструктора, придётся заимплементить ещё и move-конструктор (в main он не используется, но для полной картинки необходим).

Написать на сырых поинтерах можно. Более того, это было бы даже более поучительно, чем использовать unique_ptr, ведь задача больше обучающая, чем реальная... Но стало лень после того, как понял, что по-хорошему помимо конструктора, деструктора, придётся заимплементить ещё и move-конструктор (в main он не используется, но для полной картинки необходим).
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.