Здарова!
union u
{
list<int> l;
......
};
MSVC 2008 выдает ошибку , т.к. член объединения имеет конструктор копирования.
Собственно, вопрос не в конкретном списке. А вообще — почему член объединения не может иметь конструктор копирования?(и что ещё он не может содержать?)
Здравствуйте, ZigaZaga, Вы писали:
ZZ>...
ZZ>Собственно, вопрос не в конкретном списке. А вообще — почему член объединения не может иметь конструктор копирования?(и что ещё он не может содержать?)
Вот что говорится об объединениях в стандарте:
9.5/1
...A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of reference type, the program is ill-formed.
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, ZigaZaga, Вы писали:
ZZ>>...
ZZ>>Собственно, вопрос не в конкретном списке. А вообще — почему член объединения не может иметь конструктор копирования?(и что ещё он не может содержать?)
R>Вот что говорится об объединениях в стандарте:
R>R>9.5/1
R>...A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of reference type, the program is ill-formed.
Спасибо Сергей.
а почему именно нельзя? в смысле, чем это объясняется? что такого в нетривиальных конструкторах???
Здравствуйте, ZigaZaga, Вы писали:
ZZ>Здравствуйте, rg45, Вы писали:
R>>Здравствуйте, ZigaZaga, Вы писали:
ZZ>>>...
ZZ>>>Собственно, вопрос не в конкретном списке. А вообще — почему член объединения не может иметь конструктор копирования?(и что ещё он не может содержать?)
R>>Вот что говорится об объединениях в стандарте:
R>>R>>9.5/1
R>>...A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of reference type, the program is ill-formed.
ZZ>Спасибо Сергей.
ZZ>а почему именно нельзя? в смысле, чем это объясняется? что такого в нетривиальных конструкторах???
Ну представь даже самую простую ситуацию: ты создаешь объединение, содержащее два члена типа
std::list<int>. Ты можешь захотеть определить у этого объединения конструктор по умолчанию, в котором выполнить инициализацию обоих членов. В результате получится что память, выделенная при инициализации первого члена, будет навсегда потеряна при инциализации второго члена. А случаи ведь могут быть куда более сложные. В общем, чехарда и бессмыслица получается такая, что правильней эту возможность запретить. Тем более, что если очень нужно, то обходные пути всегда можно найти
Здравствуйте, ZigaZaga, Вы писали:
ZZ>а почему именно нельзя? в смысле, чем это объясняется? что такого в нетривиальных конструкторах???
Очень просто:
union U { X x; Y y; };
U u; // если у X или Y есть конструктор без параметров - кого из них вызывать?
U v(u); // если есть конструктор(ы) копирования - кого из них вызывать?
u = v; // если есть оператор(ы) присваивания - кого из них вызывать?
А в тех случаях, когда нужно реализовывать вариантный тип — например, boost::variant<...> — прибегают к эмуляции объединения.
Вот примерно так:
class U
{
private:
// эмуляция объединения - POD подходящего размера
char raw[max(sizeof(X), sizeof(Y))]; // нужно ещё позаботиться о выравнивании...
// информация о текущем типе (например, тэг; хотя удобнее может быть и статический объект-хелпер)
enum Actual { IsNothing, IsX, IsY } tag;
public:
U() : tag(IsNothing) {}
U(const X& x) : tag(IsNothing) { assign(x); }
U(const Y& y) : tag(IsNothing) { assign(y); }
U(const U& u) : tag(IsNothing) { assign(u); }
~U() { destroy(); }
U& operator = (const X& x) { assign(x); return *this; }
U& operator = (const Y& y) { assign(y); return *this; }
U& operator = (const U& u) { assign(u); return *this; }
operator X& () const { check(IsX); return *(X*)raw; }
operator Y& () const { check(IsY); return *(Y*)raw; }
const std::type_info& type() const
{
switch(tag)
{
case IsNothing: return typeid(void);
case IsX: return typeid(X);
case IsY: return typeid(Y);
}
}
private:
void destroy()
{
switch(tag)
{
case IsX: ((X*)raw)->~X(); break;
case IsY: ((Y*)raw)->~Y(); break;
}
tag = IsNothing;
}
void assign(const X& x) // простой способ
{
destroy(); new(raw)X(x); tag=IsX;
}
void assign(const Y& y) // чуть более громоздкий способ
{
if(tag!=IsY) { destroy(); new(raw)Y(y); tag=IsY; }
else { *(Y*)raw = y; }
}
void assign(const U& u)
{
switch(u.tag)
{
case IsNothing: destroy(); break;
case IsX: assign((X&)u); break;
case IsY: assign((Y&)u); break;
}
}
void check(Actual t) const
{
if(tag != t) throw std::bad_cast();
}
};