Громоздкость перегрузки конструктора копирования (и оператора присваивания)
От: _hum_ Беларусь  
Дата: 04.11.15 14:00
Оценка:
Появились ли к настоящему моменту какие-нибудь эффективные способы написания перегрузок для соответствующих методов, позволяющие сократить до минимума тупое перечисление наподобие
m_field_val = Instance.m_field_val;


Например, если в классе очень много копируемых полей, и очень мало указателей (unique owners), то такое перечисление выглядит очень дико (к тому же вероятность пропустить, не дописать и т.п. многократно увеличивается).

Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?

На всякий случай — у меня внутри класса гетерогенный контейнер (контейнер указателей на базовый класс, от которого наследуются разные классы объектов). Соответственно, именно для него приходится ручками писать копирование (а создавать отдельный копируемый класс для него как-то лень).
Re: Громоздкость перегрузки конструктора копирования (и оператора присваивания)
От: Warturtle  
Дата: 04.11.15 14:54
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Появились ли к настоящему моменту какие-нибудь эффективные способы написания перегрузок для соответствующих методов, позволяющие сократить до минимума тупое перечисление наподобие

__>
__>m_field_val = Instance.m_field_val; 
__>


__>Например, если в классе очень много копируемых полей, и очень мало указателей (unique owners), то такое перечисление выглядит очень дико (к тому же вероятность пропустить, не дописать и т.п. многократно увеличивается).


__>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?


__>На всякий случай — у меня внутри класса гетерогенный контейнер (контейнер указателей на базовый класс, от которого наследуются разные классы объектов). Соответственно, именно для него приходится ручками писать копирование (а создавать отдельный копируемый класс для него как-то лень).

Можно сделать такое с помощью boost::fusion::for_each, предварительно адаптировав класс макросом вроде BOOST_FUSION_ADAPT_STRUCT. Например нужно сделать некоторые покомпонентные операции с большой структурою:
BOOST_FUSION_ADAPT_STRUCT(
    CHARFORMAT2,
    (DWORD,        dwMask)
    (DWORD,        dwEffects)
    (LONG,        yHeight)
    (LONG,        yOffset)
    (COLORREF,    crTextColor)
    (BYTE,        bCharSet)
    (BYTE,        bPitchAndFamily)
    (WORD,        wWeight)
    (SHORT,        sSpacing)
    (COLORREF,    crBackColor)
    (LCID,        lcid)
    (SHORT,        sStyle)
    (WORD,        wKerning)
    (BYTE,        bUnderlineType)
    (BYTE,        bAnimation)
    (BYTE,        bRevAuthor)
);

inline bool operator <(CHARFORMAT2 const & a, CHARFORMAT2 const & b)
{
    return fusion::less< CHARFORMAT2, CHARFORMAT2 >(a, b);
}

inline bool operator ==(CHARFORMAT2 const & a, CHARFORMAT2 const & b)
{
    return fusion::equal_to< CHARFORMAT2, CHARFORMAT2 >(a, b);
}

struct SequenceHasher
{
    SequenceHasher(size_t & seed) : m_seed(seed)
    {
    }
    template< class MemberT >
    void operator ()(MemberT const & data) const
    {
        boost::hash_combine(m_seed, data);
    }
    template< class SeqT >
    static inline size_t Calculate(SeqT const & seq)
    {
        static size_t const s_seed = ::GetTickCount();
        size_t seed = s_seed;
        fusion::for_each(seq, SequenceHasher(seed));
        return seed;
    }
private:
    size_t & m_seed;
};

namespace boost
{
    inline size_t hash_value(CHARFORMAT2 const & seq)
    {
        return SequenceHasher::Calculate(seq);
    }
}
Re: Громоздкость перегрузки конструктора копирования (и оператора присваивания)
От: Vain Россия google.ru
Дата: 04.11.15 15:22
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Появились ли к настоящему моменту какие-нибудь эффективные способы написания перегрузок для соответствующих методов, позволяющие сократить до минимума тупое перечисление наподобие

__>
__>m_field_val = Instance.m_field_val; 
__>

А почему бы все эти поля просто убрать в структуру без всяких перегрузок и использовать что-то вроде такого:
data = Instance.data

?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: Громоздкость перегрузки конструктора копирования (и оператора присваивания)
От: T4r4sB Россия  
Дата: 04.11.15 15:24
Оценка: -3
Здравствуйте, _hum_, Вы писали:

__>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?


Хехе, а вот в Аде там по умолчанию при копировании сначала делается простое побитовое копирование, потом для всех полей вызывается метод Adjust, а потом уже для самого класса вызывается метод Adjust. И да, писать почти одно и то же два раза (я про конструктор копирования и оператор =) в ней не надо,
Но это же противоречит принципу "не платить за то, что не заказывал", хотя экономия тут полторы спички.
Re: Громоздкость перегрузки конструктора копирования (и оператора присваивания)
От: B0FEE664  
Дата: 04.11.15 17:58
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?


Давно существует:
MyClass& MyClass::operator=(const MyClass& rObj)
{
    if( this != &rObj )
    {
       this->~MyClass();
       new (this) MyClass(rObj);
    }
    return *this;
}

но я почему-то страшусь таких конструкций.
И каждый день — без права на ошибку...
Re[2]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: T4r4sB Россия  
Дата: 04.11.15 18:15
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, _hum_, Вы писали:


__>>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?


BFE>Давно существует:


ТС не то спрашивал.
Но я так и делаю, как ты написал.
Конструктор копирования должен быть ноэксепт для этого, конечно.
Re[2]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: _hum_ Беларусь  
Дата: 04.11.15 18:15
Оценка:
Здравствуйте, Warturtle, Вы писали:

W>Здравствуйте, _hum_, Вы писали:


__>>Появились ли к настоящему моменту какие-нибудь эффективные способы написания перегрузок для соответствующих методов, позволяющие сократить до минимума тупое перечисление наподобие

__>>
__>>m_field_val = Instance.m_field_val; 
__>>


__>>Например, если в классе очень много копируемых полей, и очень мало указателей (unique owners), то такое перечисление выглядит очень дико (к тому же вероятность пропустить, не дописать и т.п. многократно увеличивается).


__>>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?


__>>На всякий случай — у меня внутри класса гетерогенный контейнер (контейнер указателей на базовый класс, от которого наследуются разные классы объектов). Соответственно, именно для него приходится ручками писать копирование (а создавать отдельный копируемый класс для него как-то лень).

W>Можно сделать такое с помощью boost::fusion::for_each, предварительно адаптировав класс макросом вроде BOOST_FUSION_ADAPT_STRUCT. Например нужно сделать некоторые покомпонентные операции с большой структурою:
W>
W>BOOST_FUSION_ADAPT_STRUCT(
W>    CHARFORMAT2,
W>    (DWORD,        dwMask)
W>    (DWORD,        dwEffects)
W>    (LONG,        yHeight)
W>    (LONG,        yOffset)
W>    (COLORREF,    crTextColor)
W>    (BYTE,        bCharSet)
W>    (BYTE,        bPitchAndFamily)
W>    (WORD,        wWeight)
W>    (SHORT,        sSpacing)
W>    (COLORREF,    crBackColor)
W>    (LCID,        lcid)
W>    (SHORT,        sStyle)
W>    (WORD,        wKerning)
W>    (BYTE,        bUnderlineType)
W>    (BYTE,        bAnimation)
W>    (BYTE,        bRevAuthor)
W>);

W>inline bool operator <(CHARFORMAT2 const & a, CHARFORMAT2 const & b)
W>{
W>    return fusion::less< CHARFORMAT2, CHARFORMAT2 >(a, b);
W>}

W>inline bool operator ==(CHARFORMAT2 const & a, CHARFORMAT2 const & b)
W>{
W>    return fusion::equal_to< CHARFORMAT2, CHARFORMAT2 >(a, b);
W>}

W>struct SequenceHasher
W>{
W>    SequenceHasher(size_t & seed) : m_seed(seed)
W>    {
W>    }
W>    template< class MemberT >
W>    void operator ()(MemberT const & data) const
W>    {
W>        boost::hash_combine(m_seed, data);
W>    }
W>    template< class SeqT >
W>    static inline size_t Calculate(SeqT const & seq)
W>    {
W>        static size_t const s_seed = ::GetTickCount();
W>        size_t seed = s_seed;
W>        fusion::for_each(seq, SequenceHasher(seed));
W>        return seed;
W>    }
W>private:
W>    size_t & m_seed;
W>};

W>namespace boost
W>{
W>    inline size_t hash_value(CHARFORMAT2 const & seq)
W>    {
W>        return SequenceHasher::Calculate(seq);
W>    }
W>}
W>


да, но, если я правильно понял, все равно приходится ручками работать — перечислять все нужные поля в макросе адаптации
Re[3]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: T4r4sB Россия  
Дата: 04.11.15 18:17
Оценка: -2 :)
Здравствуйте, _hum_, Вы писали:

__>да, но, если я правильно понял, все равно приходится ручками работать — перечислять все нужные поля в макросе адаптации


Подожди ещё лет 10, и дохлый страус наконец-то добавит рефлексию времени компиляции, и потом ещё 5, и она появится в Студии, и ещё 5, и новая Студия перестанет глючить.
Re[2]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: _hum_ Беларусь  
Дата: 04.11.15 18:21
Оценка:
Здравствуйте, Vain, Вы писали:

V>Здравствуйте, _hum_, Вы писали:


__>>Появились ли к настоящему моменту какие-нибудь эффективные способы написания перегрузок для соответствующих методов, позволяющие сократить до минимума тупое перечисление наподобие

__>>
__>>m_field_val = Instance.m_field_val; 
__>>

V>А почему бы все эти поля просто убрать в структуру без всяких перегрузок и использовать что-то вроде такого:
V>
V>data = Instance.data
V>

V>?
потому что, во-первых, это техническая структура, а во-вторых, если поля связаны между собою (например, объект одного поля имеет ссылки на объект другого поля за пределами data), то все еще больше усложнится. уж лучше тогда обернуть указатели в какие-нибудь смарт-поинтеры, которые автоматически при копировании клонируют свои объекты (кстати, а такого плана умные указатели вообще существуют, например, в том же бусте?).
Re[2]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: _hum_ Беларусь  
Дата: 04.11.15 18:28
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, _hum_, Вы писали:


__>>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?


TB>Хехе, а вот в Аде там по умолчанию при копировании сначала делается простое побитовое копирование, потом для всех полей вызывается метод Adjust, а потом уже для самого класса вызывается метод Adjust.


во-во. что-то похожее хотелось бы организовать


TB> И да, писать почти одно и то же два раза (я про конструктор копирования и оператор =) в ней не надо,


так в с++ тоже во многих случаях (хотя и не всегда) копирование можно через присваивание определить:
CopyCtr(const CopyCtr& Inst)
{
   operator=(Inst);
}
Re[2]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: _hum_ Беларусь  
Дата: 04.11.15 18:35
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, _hum_, Вы писали:


__>>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?


BFE>Давно существует:

BFE>
BFE>MyClass& MyClass::operator=(const MyClass& rObj)
BFE>{
BFE>    if( this != &rObj )
BFE>    {
       this->>~MyClass();
BFE>       new (this) MyClass(rObj);
BFE>    }
BFE>    return *this;
BFE>}
BFE>

BFE>но я почему-то страшусь таких конструкций.

да, это немного не то — это как определить присваивание через конструктор копирования

кста, давече по поводу placement new натолкнулся на строгое предупреждение — мол, вам никто не гарантирует, что объект будет размещен именно с начала указателя на буфер. при размещении могут еще учитываться всякие выравнивания и проч.
потому я бы тоже побоялся такое использовать.
Re[3]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: T4r4sB Россия  
Дата: 04.11.15 18:36
Оценка:
Здравствуйте, _hum_, Вы писали:

__>так в с++ тоже во многих случаях (хотя и не всегда) копирование можно через присваивание определить:

__>
__>CopyCtr(const CopyCtr& Inst)
__>{
__>   operator=(Inst);
__>}
__>


Ты, наверное, хотел сказать так:

MyClass (const MyClass & other) : MyClass () // сначала надо таки инициализировать как-то
{
   operator=(other);
}
Re[3]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: T4r4sB Россия  
Дата: 04.11.15 18:37
Оценка:
Здравствуйте, _hum_, Вы писали:
__>кста, давече по поводу placement new натолкнулся на строгое предупреждение — мол, вам никто не гарантирует, что объект будет размещен именно с начала указателя на буфер. при размещении могут еще учитываться всякие выравнивания и проч.
__>потому я бы тоже побоялся такое использовать.

Ну дык нефиг невыровненные указатели использовать.
Re[4]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: _hum_ Беларусь  
Дата: 04.11.15 18:39
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, _hum_, Вы писали:


__>>да, но, если я правильно понял, все равно приходится ручками работать — перечислять все нужные поля в макросе адаптации


TB>Подожди ещё лет 10, и дохлый страус наконец-то добавит рефлексию времени компиляции, и потом ещё 5, и она появится в Студии, и ещё 5, и новая Студия перестанет глючить.


а в новом стандарте ничего по этому поводу не придумали? я слышал, там какие-то новшества вводили, связанные с дефолтными конструкторами и операторами присваивания. вот и надеялся, что может, и эту проблему разрулили.
Re[4]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: _hum_ Беларусь  
Дата: 04.11.15 18:42
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, _hum_, Вы писали:

__>>кста, давече по поводу placement new натолкнулся на строгое предупреждение — мол, вам никто не гарантирует, что объект будет размещен именно с начала указателя на буфер. при размещении могут еще учитываться всякие выравнивания и проч.
__>>потому я бы тоже побоялся такое использовать.

TB>Ну дык нефиг невыровненные указатели использовать.


извиняюсь, а как в с++ можно удостовериться, что они выровнены нужным образом?
и еще, это единственное условие, или еще какие-то есть на корректность использования placement new?
Re[4]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: _hum_ Беларусь  
Дата: 04.11.15 18:46
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, _hum_, Вы писали:


__>>так в с++ тоже во многих случаях (хотя и не всегда) копирование можно через присваивание определить:

__>>
__>>CopyCtr(const CopyCtr& Inst)
__>>{
__>>   operator=(Inst);
__>>}
__>>


TB>Ты, наверное, хотел сказать так:


TB>
TB>MyClass (const MyClass & other) : MyClass () // сначала надо таки инициализировать как-то
TB>{
TB>   operator=(other);
TB>}
TB>


зачем? присваивание и есть инициализация.

п.с. и вообще код
MyClass (const MyClass & other) : MyClass ()

разве пройдет?
Re[3]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: B0FEE664  
Дата: 04.11.15 18:47
Оценка:
Здравствуйте, _hum_, Вы писали:

__>>>Может, появилась какая-нить возможность принудительно вызывать конструктор копирования по умолчанию внутри перегрузки конструктора копирования?

__>да, это немного не то — это как определить присваивание через конструктор копирования

А, чёрт! Дак это, делегирующие конструкторы вам в помощь.
И каждый день — без права на ошибку...
Re[5]: Громоздкость перегрузки конструктора копирования (и о
От: B0FEE664  
Дата: 04.11.15 19:02
Оценка:
Здравствуйте, _hum_, Вы писали:

__>п.с. и вообще код

__>
__>MyClass (const MyClass & other) : MyClass ()
__>

__>разве пройдет?

Да. Это нововведение С++11. см. здесь
И каждый день — без права на ошибку...
Отредактировано 04.11.2015 19:11 B0FEE664 . Предыдущая версия .
Re[5]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: T4r4sB Россия  
Дата: 04.11.15 19:06
Оценка:
Здравствуйте, _hum_, Вы писали:

__>извиняюсь, а как в с++ можно удостовериться, что они выровнены нужным образом?


Ну можно завести структуру CheckAlign{ char c; MyClass obj; }, тогда sizeof(CheckAlign)-sizeof(MyClass) будет выравниванием, осталось проверить, что значение указателя делится на это выравнивание.
Re[5]: Громоздкость перегрузки конструктора копирования (и оператора присваивани
От: T4r4sB Россия  
Дата: 04.11.15 19:10
Оценка:
Здравствуйте, _hum_, Вы писали:

__>зачем? присваивание и есть инициализация.


Затем, что присваивание не инициализация. Присваивание ещё и смотрит на то, что было в объекте до этого. Например, в умном указателе, такой утрированный пример:

clever_ptr& operator = (const clever_ptr& other)
{
  if (!m_ptr) // опа опа
    m_ptr = new T(*other.m_ptr);
  else
    *m_ptr = *other.m_ptr;
}


Поэтому очень важно, чтобы перед вызовом = объект находился в самосогласованном состоянии. Вызов пустого конструктора это и делает.

__>п.с. и вообще код

__>
__>MyClass (const MyClass & other) : MyClass ()
__>

__>разве пройдет?

Это делегирующие конструкторы. В ++03 нет, не пройдёт.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.