Aracılığıyla paylaş


union

Dekont

C++17 ve sonraki sürümlerde, std::variantclass türü güvenli bir unionalternatiftir.

A union , tüm üyelerin aynı bellek konumunu paylaştığı kullanıcı tanımlı bir türdür. Bu tanım, herhangi bir zamanda, bir union öğesinin üye listesinden en fazla bir nesne içerebileceği anlamına gelir. Ayrıca, bir üyenin kaç üyesi union olursa olsun, her zaman en büyük üyeyi depolamak için yeterli bellek kullandığı anlamına gelir.

Bir union , çok fazla nesneniz ve sınırlı belleğiniz olduğunda bellek tasarrufu için yararlı olabilir. Ancak, doğru union kullanmak için ek özen gerektirir. Her zaman atadığınız üyeye erişmenizi sağlamak sizin sorumluluğundadır. Herhangi bir üye türünün önemsiz bir eksisistructvarsa veya bu üyeyi açıkça dolandırmakstruct ve yok etmek için kod yazmanız gerekir. kullanmadan unionönce, çözmeye çalıştığınız sorunun temel class ve türetilmiş class türler kullanılarak daha iyi ifade edilip edilemeyeceğini göz önünde bulundurun.

Sözdizimi

uniontagTercih{member-list};

Parametreler

tag
öğesine verilen uniontür adı.

member-list
öğesinin union içerebileceği üyeler.

Bir union

anahtar sözcüğünü kullanarak bildirimini unionunion başlatın ve üye listesini küme ayracı içine alın:

// declaring_a_union.cpp
union RecordType    // Declare a simple union type
{
    char   ch;
    int    i;
    long   l;
    float  f;
    double d;
    int *int_ptr;
};

int main()
{
    RecordType t;
    t.i = 5; // t holds an int
    t.f = 7.25; // t now holds a float
}

Bir union

Önceki örnekte, erişim sağlayan herhangi bir kodun union verileri hangi üyenin barındırdığını bilmesi gerekir. Bu sorunun en yaygın çözümü, ayrımcı unionolarak adlandırılır. öğesini içine structalır union ve içinde depolanan unionüye türünü gösteren bir enum üye içerir. Aşağıdaki örnekte temel desen gösterilmektedir:

#include <queue>

using namespace std;

enum class WeatherDataType
{
    Temperature, Wind
};

struct TempData
{
    int StationId;
    time_t time;
    double current;
    double max;
    double min;
};

struct WindData
{
    int StationId;
    time_t time;
    int speed;
    short direction;
};

struct Input
{
    WeatherDataType type;
    union
    {
        TempData temp;
        WindData wind;
    };
};

// Functions that are specific to data types
void Process_Temp(TempData t) {}
void Process_Wind(WindData w) {}

void Initialize(std::queue<Input>& inputs)
{
    Input first;
    first.type = WeatherDataType::Temperature;
    first.temp = { 101, 1418855664, 91.8, 108.5, 67.2 };
    inputs.push(first);

    Input second;
    second.type = WeatherDataType::Wind;
    second.wind = { 204, 1418859354, 14, 27 };
    inputs.push(second);
}

int main(int argc, char* argv[])
{
    // Container for all the data records
    queue<Input> inputs;
    Initialize(inputs);
    while (!inputs.empty())
    {
        Input const i = inputs.front();
        switch (i.type)
        {
        case WeatherDataType::Temperature:
            Process_Temp(i.temp);
            break;
        case WeatherDataType::Wind:
            Process_Wind(i.wind);
            break;
        default:
            break;
        }
        inputs.pop();

    }
    return 0;
}

Önceki örnekte içindekinin unionInputstruct adı yoktur, bu nedenle anonimunion olarak adlandırılır. Üyelerine doğrudan öğesinin structüyesi gibi erişilebilir. Anonim kullanma hakkında daha fazla bilgi için Anonim unionunion bölümüne bakın.

Önceki örnekte, ortak bir temelden classtüretilen türleri kullanarak class da çözebildiğiniz bir sorun gösterilmektedir. Kodunuzu kapsayıcıdaki her nesnenin çalışma zamanı türüne göre dallayabilirsiniz. Kodunuzun bakımı ve anlaşılması daha kolay olabilir, ancak bir kullanmaktan uniondaha yavaş da olabilir. Ayrıca, ile unionilişkisiz türleri depolayabilirsiniz. A union , değişkenin türünü değiştirmeden depolanan değerin türünü dinamik olarak değiştirmenize union olanak tanır. Örneğin, öğeleri farklı türlerdeki farklı değerleri depolayan heterojen bir dizisi MyUnionTypeoluşturabilirsiniz.

Örnekteki öğesini Inputstruct kötüye kullanmak kolaydır. Verileri barındıran üyeye erişmek için ayrımcıyı doğru kullanmak kullanıcıya aittir. Sonraki örnekte gösterildiği gibi ve özel erişim işlevleri sağlayarak kötüye kullanımlara unionprivate karşı koruma sağlayabilirsiniz.

Kısıtlanmamış union (C++11)

C++03 ve önceki sürümlerde, union türünde kullanıcı tarafından sağlanan eksistruct, destructveyas veya atama işleçleri olmadığı sürece, türü olmayan veri üyeleri class bulunabilirstatic. C++11'de bu kısıtlamalar kaldırılır. 'ınıza unionböyle bir üye eklerseniz, derleyici kullanıcı olarak sağlanmayan özel üye işlevlerini otomatik olarak deletedişaretler. veya içinde anonimseunion, kullanıcı tarafından sağlanmayan class veya struct özel üye işlevleri olarak deletedişaretlenir.classstructunion Aşağıdaki örnekte bu durumun nasıl işleneceğini gösterilmektedir. üyelerinden union birinin bu özel işlem gerektiren bir üyesi vardır:

// for MyVariant
#include <crtdbg.h>
#include <new>
#include <utility>

// for sample objects and output
#include <string>
#include <vector>
#include <iostream>

using namespace std;

struct A
{
    A() = default;
    A(int i, const string& str) : num(i), name(str) {}

    int num;
    string name;
    //...
};

struct B
{
    B() = default;
    B(int i, const string& str) : num(i), name(str) {}

    int num;
    string name;
    vector<int> vec;
    // ...
};

enum class Kind { None, A, B, Integer };

#pragma warning (push)
#pragma warning(disable:4624)
class MyVariant
{
public:
    MyVariant()
        : kind_(Kind::None)
    {
    }

    MyVariant(Kind kind)
        : kind_(kind)
    {
        switch (kind_)
        {
        case Kind::None:
            break;
        case Kind::A:
            new (&a_) A();
            break;
        case Kind::B:
            new (&b_) B();
            break;
        case Kind::Integer:
            i_ = 0;
            break;
        default:
            _ASSERT(false);
            break;
        }
    }

    ~MyVariant()
    {
        switch (kind_)
        {
        case Kind::None:
            break;
        case Kind::A:
            a_.~A();
            break;
        case Kind::B:
            b_.~B();
            break;
        case Kind::Integer:
            break;
        default:
            _ASSERT(false);
            break;
        }
        kind_ = Kind::None;
    }

    MyVariant(const MyVariant& other)
        : kind_(other.kind_)
    {
        switch (kind_)
        {
        case Kind::None:
            break;
        case Kind::A:
            new (&a_) A(other.a_);
            break;
        case Kind::B:
            new (&b_) B(other.b_);
            break;
        case Kind::Integer:
            i_ = other.i_;
            break;
        default:
            _ASSERT(false);
            break;
        }
    }

    MyVariant(MyVariant&& other)
        : kind_(other.kind_)
    {
        switch (kind_)
        {
        case Kind::None:
            break;
        case Kind::A:
            new (&a_) A(move(other.a_));
            break;
        case Kind::B:
            new (&b_) B(move(other.b_));
            break;
        case Kind::Integer:
            i_ = other.i_;
            break;
        default:
            _ASSERT(false);
            break;
        }
        other.kind_ = Kind::None;
    }

    MyVariant& operator=(const MyVariant& other)
    {
        if (&other != this)
        {
            switch (other.kind_)
            {
            case Kind::None:
                this->~MyVariant();
                break;
            case Kind::A:
                *this = other.a_;
                break;
            case Kind::B:
                *this = other.b_;
                break;
            case Kind::Integer:
                *this = other.i_;
                break;
            default:
                _ASSERT(false);
                break;
            }
        }
        return *this;
    }

    MyVariant& operator=(MyVariant&& other)
    {
        _ASSERT(this != &other);
        switch (other.kind_)
        {
        case Kind::None:
            this->~MyVariant();
            break;
        case Kind::A:
            *this = move(other.a_);
            break;
        case Kind::B:
            *this = move(other.b_);
            break;
        case Kind::Integer:
            *this = other.i_;
            break;
        default:
            _ASSERT(false);
            break;
        }
        other.kind_ = Kind::None;
        return *this;
    }

    MyVariant(const A& a)
        : kind_(Kind::A), a_(a)
    {
    }

    MyVariant(A&& a)
        : kind_(Kind::A), a_(move(a))
    {
    }

    MyVariant& operator=(const A& a)
    {
        if (kind_ != Kind::A)
        {
            this->~MyVariant();
            new (this) MyVariant(a);
        }
        else
        {
            a_ = a;
        }
        return *this;
    }

    MyVariant& operator=(A&& a)
    {
        if (kind_ != Kind::A)
        {
            this->~MyVariant();
            new (this) MyVariant(move(a));
        }
        else
        {
            a_ = move(a);
        }
        return *this;
    }

    MyVariant(const B& b)
        : kind_(Kind::B), b_(b)
    {
    }

    MyVariant(B&& b)
        : kind_(Kind::B), b_(move(b))
    {
    }

    MyVariant& operator=(const B& b)
    {
        if (kind_ != Kind::B)
        {
            this->~MyVariant();
            new (this) MyVariant(b);
        }
        else
        {
            b_ = b;
        }
        return *this;
    }

    MyVariant& operator=(B&& b)
    {
        if (kind_ != Kind::B)
        {
            this->~MyVariant();
            new (this) MyVariant(move(b));
        }
        else
        {
            b_ = move(b);
        }
        return *this;
    }

    MyVariant(int i)
        : kind_(Kind::Integer), i_(i)
    {
    }

    MyVariant& operator=(int i)
    {
        if (kind_ != Kind::Integer)
        {
            this->~MyVariant();
            new (this) MyVariant(i);
        }
        else
        {
            i_ = i;
        }
        return *this;
    }

    Kind GetKind() const
    {
        return kind_;
    }

    A& GetA()
    {
        _ASSERT(kind_ == Kind::A);
        return a_;
    }

    const A& GetA() const
    {
        _ASSERT(kind_ == Kind::A);
        return a_;
    }

    B& GetB()
    {
        _ASSERT(kind_ == Kind::B);
        return b_;
    }

    const B& GetB() const
    {
        _ASSERT(kind_ == Kind::B);
        return b_;
    }

    int& GetInteger()
    {
        _ASSERT(kind_ == Kind::Integer);
        return i_;
    }

    const int& GetInteger() const
    {
        _ASSERT(kind_ == Kind::Integer);
        return i_;
    }

private:
    Kind kind_;
    union
    {
        A a_;
        B b_;
        int i_;
    };
};
#pragma warning (pop)

int main()
{
    A a(1, "Hello from A");
    B b(2, "Hello from B");

    MyVariant mv_1 = a;

    cout << "mv_1 = a: " << mv_1.GetA().name << endl;
    mv_1 = b;
    cout << "mv_1 = b: " << mv_1.GetB().name << endl;
    mv_1 = A(3, "hello again from A");
    cout << R"aaa(mv_1 = A(3, "hello again from A"): )aaa" << mv_1.GetA().name << endl;
    mv_1 = 42;
    cout << "mv_1 = 42: " << mv_1.GetInteger() << endl;

    b.vec = { 10,20,30,40,50 };

    mv_1 = move(b);
    cout << "After move, mv_1 = b: vec.size = " << mv_1.GetB().vec.size() << endl;

    cout << endl << "Press a letter" << endl;
    char c;
    cin >> c;
}

bir union başvuru depolayamaz. A union ayrıca devralmayı desteklemez. Başka bir union deyişle, temel classolarak kullanamaz veya başka classbir öğesinden devralamaz ya da sanal işlevlere sahip olamazsınız.

Başlatma union

Ayraç içine alınmış bir union ifade atayarak aynı deyimde bir bildirebilir ve başlatabilirsiniz. İfade değerlendirilir ve öğesinin ilk alanına unionatanır.

#include <iostream>
using namespace std;

union NumericType
{
    short       iValue;
    long        lValue;
    double      dValue;
};

int main()
{
    union NumericType Values = { 10 };   // iValue = 10
    cout << Values.iValue << endl;
    Values.dValue = 3.1416;
    cout << Values.dValue << endl;
}
/* Output:
10
3.141600
*/

NumericTypeunion aşağıdaki şekilde gösterildiği gibi bellekte (kavramsal olarak) düzenlenmiştir:

Diagram that shows the overlapping storage of data in the NumericType union.

Diyagramda 8 bayt veri gösterilir. Çift tür dValue, 8 bayt'ın tamamını kaplar. long lValue türü ilk 4 baytı kaplar. iValue kısa türü ilk bayta yer alır.

Anonim union

Anonimunion, veya declarator-listolmadan bildirilen bir class-name addır.

union { member-list }

Anonim union olarak bildirilen adlar, üye olmayan değişkenler gibi doğrudan kullanılır. Anonim olarak union bildirilen adların çevresindeki kapsamda benzersiz olması gerektiği anlamına gelir.

Anonim union bir öğe şu kısıtlamalara tabidir:

  • Dosya veya ad alanı kapsamında bildirildiyse, olarak da bildirilmelidir static.
  • Yalnızca public üyelere sahip olabilir; anonim union bir öğede ve protected üyelerine sahip olmak private hata oluşturur.
  • Üye işlevleri olamaz.

Ayrıca bkz.

Sınıflar ve Yapılar
Anahtar Sözcükler
class
struct