29 Kasım 2019 Cuma

Union

Tanımlama
Şöyle yaparız.
union AUnion {
  struct CharBuf {
    char *buf;
    size_t len;
  } charbuf;
  uint8_t num;
  double fp_num;
};
Bitfield ile de tanımlanabilir.
union {
  uint32_t cw          : 13;
  struct {
    uint32_t setting4  : 4;
    uint32_t cmd       : 9;
  };
} control;
Bellek Alanı
En büyük elemanı sığdıracak kadar bellek ayrılır. Açıklaması şöyle.
The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.
Tüm farklı tipler aynı adresten başlarlar. Dolayısıyla aşağıdaki önerme doğrudur.
&u.num == &u.fp_num == &u.charbuf == &u
Union İçinde Nesne Varsa Constructor'ı Otomatik Çağrılmaz
Örnek
Elimizde şöyle bir kod olsun.
struct A
{
  A() {std::cout << "A()\n";}
  ~A() {std::cout << "~A()\n";}
};

union B
{
  A a;
  B() {}
  ~B() {}
};

int main()
{
  B b;
}
Açıklaması şöyle.
Here, B b; prints nothing, because a is not constructed nor destructed.

If B was a struct, B() would call A(), and ~B() would call ~A(), and you wouldn't be able to prevent that.
Union İçindeki Sadece Tek Bir Alana Default Value Atanabilir
Örnek
Şu kod derlenmez
union U {
  int a = 1;
  int b = 0;
};


U u;                 // what's the value of u.a ? what's the value of u.b ? 
assert(u.a != u.b);  // knowing that this assert should always fail. 
Şu kod derlenir
struct A 
{
  int x;
};

union U 
{
  A a;        // this is fine, since you did not explicitly defined a
              // default constructor for A, the compiler can skip 
              // initializing a, even though A has an implicit default
              // constructor
  int b = 0;
};
Union Parametre Olarak Geçilmemeli
Açıklaması şöyle.
The following is not a valid fragment (because the union type is not visible within function f)
Şu kod yanlış.
struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 * p1, struct t2 * p2)
{
  if (p1->m < 0)
    p2->m = -p2->m;
  return p1->m;
}
int g()
{
  union {
    struct t1 s1;
    struct t2 s2;
  } u;
  /* ... */
  return f(&u.s1, &u.s2);
}
Discriminated Union
Aslında std::variant ile aynı şey sanırım. Elimizde bir union olsun.
struct Result {
  union {
    int    i_res;
    double d_res;
  };
  enum { IS_INT, IS_DOUBLE } u_tag;

  
  Result(int i)  : i_res{i}, u_tag{IS_INT} {}
  Result(double d) : d_res{d}, u_tag{IS_DOUBLE} {}

  auto& operator=(int i)
    { i_res = i; u_tag = IS_INT;    return *this; }
  auto& operator=(double d)
    { d_res = d; u_tag = IS_DOUBLE; return *this; }
};
Şöyle yaparız.
std::function<Result(double)> cb;

cb = myfunction;
auto r = cb(1.0);
assert(r.u_tag == Result::IS_INT);
std::cout << r.i_res << '\n';

Hiç yorum yok:

Yorum Gönder