почему union не может содержать list<int>
От: ZigaZaga  
Дата: 05.01.10 20:33
Оценка:
Здарова!

union u
{
   list<int> l;
   ......
};


MSVC 2008 выдает ошибку , т.к. член объединения имеет конструктор копирования.
Собственно, вопрос не в конкретном списке. А вообще — почему член объединения не может иметь конструктор копирования?(и что ещё он не может содержать?)
Re: почему union не может содержать list<int>
От: rg45 СССР  
Дата: 05.01.10 21:18
Оценка: 2 (1)
Здравствуйте, 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.

--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: почему union не может содержать list<int>
От: ZigaZaga  
Дата: 05.01.10 21:39
Оценка:
Здравствуйте, 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.

Спасибо Сергей.

а почему именно нельзя? в смысле, чем это объясняется? что такого в нетривиальных конструкторах???
Re[3]: почему union не может содержать list<int>
От: rg45 СССР  
Дата: 05.01.10 22:02
Оценка: 2 (1)
Здравствуйте, 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>. Ты можешь захотеть определить у этого объединения конструктор по умолчанию, в котором выполнить инициализацию обоих членов. В результате получится что память, выделенная при инициализации первого члена, будет навсегда потеряна при инциализации второго члена. А случаи ведь могут быть куда более сложные. В общем, чехарда и бессмыслица получается такая, что правильней эту возможность запретить. Тем более, что если очень нужно, то обходные пути всегда можно найти
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: почему union не может содержать list<int>
От: Кодт Россия  
Дата: 05.01.10 22:09
Оценка: 3 (1)
Здравствуйте, 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();
  }
};
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.