Udostępnij za pośrednictwem


Kontenery STL/CLR

Biblioteka STL/CLR składa się z kontenerów podobnych do tych znalezionych w standardowej bibliotece języka C++, ale działa w środowisku zarządzanym programu .NET Framework. Nie jest ona aktualna w rzeczywistej standardowej bibliotece języka C++ i jest utrzymywana w celu zapewnienia starszej obsługi.

Ten dokument zawiera omówienie kontenerów w bibliotece STL/CLR, takich jak wymagania dotyczące elementów kontenera, typy elementów, które można wstawić do kontenerów, oraz problemy z własnością elementów w kontenerach. W razie potrzeby wymieniono różnice między natywną biblioteką standardową języka C++ a biblioteką STL/CLR.

Wymagania dotyczące elementów kontenera

Wszystkie elementy wstawione do kontenerów STL/CLR muszą przestrzegać określonych wytycznych. Aby uzyskać więcej informacji, zobacz Wymagania dotyczące elementów kontenera STL/CLR.

Prawidłowe elementy kontenera

Kontenery STL/CLR mogą przechowywać jeden z dwóch typów elementów:

  • Dojście do typów referencyjnych.

  • Typy odwołań.

  • Typy wartości bez skrzynki odbiorczej.

Nie można wstawić typów wartości w polu do żadnego z kontenerów STL/CLR.

Dojścia do typów odwołań

Uchwyt można wstawić do typu odwołania do kontenera STL/CLR. Uchwyt w języku C++, który jest przeznaczony dla środowiska CLR, jest analogiczny do wskaźnika w natywnym języku C++. Aby uzyskać więcej informacji, zobacz Handle to Object Operator (^).

Przykład

W poniższym przykładzie pokazano, jak wstawić uchwyt do obiektu Employee w interfejsie wiersza polecenia::set.

// cliext_container_valid_reference_handle.cpp
// compile with: /clr

#include <cliext/set>

using namespace cliext;
using namespace System;

ref class Employee
{
public:
    // STL/CLR containers might require a public constructor, so it
    // is a good idea to define one.
    Employee() :
        name(nullptr),
        employeeNumber(0) { }

    // All STL/CLR containers require a public copy constructor.
    Employee(const Employee% orig) :
        name(orig.name),
        employeeNumber(orig.employeeNumber) { }

    // All STL/CLR containers require a public assignment operator.
    Employee% operator=(const Employee% orig)
    {
        if (this != %orig)
        {
            name = orig.name;
            employeeNumber = orig.employeeNumber;
        }

        return *this;
    }

    // All STL/CLR containers require a public destructor.
    ~Employee() { }

    // Associative containers such as maps and sets
    // require a comparison operator to be defined
    // to determine proper ordering.
    bool operator<(const Employee^ rhs)
    {
        return (employeeNumber < rhs->employeeNumber);
    }

    // The employee's name.
    property String^ Name
    {
        String^ get() { return name; }
        void set(String^ value) { name = value; }
    }

    // The employee's employee number.
    property int EmployeeNumber
    {
        int get() { return employeeNumber; }
        void set(int value) { employeeNumber = value; }
    }

private:
    String^ name;
    int employeeNumber;
};

int main()
{
    // Create a new employee object.
    Employee^ empl1419 = gcnew Employee();
    empl1419->Name = L"Darin Lockert";
    empl1419->EmployeeNumber = 1419;

    // Add the employee to the set of all employees.
    set<Employee^>^ emplSet = gcnew set<Employee^>();
    emplSet->insert(empl1419);

    // List all employees of the company.
    for each (Employee^ empl in emplSet)
    {
        Console::WriteLine("Employee Number {0}: {1}",
            empl->EmployeeNumber, empl->Name);
    }

    return 0;
}

Typy odwołań

Istnieje również możliwość wstawienia typu odwołania (zamiast uchwytu do typu odwołania) do kontenera STL/CLR. Główna różnica polega na tym, że po usunięciu kontenera typów odwołań destruktor jest wywoływany dla wszystkich elementów wewnątrz tego kontenera. W kontenerze dojść do typów referencyjnych destruktory dla tych elementów nie będą wywoływane.

Przykład

W poniższym przykładzie pokazano, jak wstawić obiekt Employee do obiektu cliext::set.

// cliext_container_valid_reference.cpp
// compile with: /clr

#include <cliext/set>

using namespace cliext;
using namespace System;

ref class Employee
{
public:
    // STL/CLR containers might require a public constructor, so it
    // is a good idea to define one.
    Employee() :
        name(nullptr),
        employeeNumber(0) { }

    // All STL/CLR containers require a public copy constructor.
    Employee(const Employee% orig) :
        name(orig.name),
        employeeNumber(orig.employeeNumber) { }

    // All STL/CLR containers require a public assignment operator.
    Employee% operator=(const Employee% orig)
    {
        if (this != %orig)
        {
            name = orig.name;
            employeeNumber = orig.employeeNumber;
        }

        return *this;
    }

    // All STL/CLR containers require a public destructor.
    ~Employee() { }

    // Associative containers such as maps and sets
    // require a comparison operator to be defined
    // to determine proper ordering.
    bool operator<(const Employee^ rhs)
    {
        return (employeeNumber < rhs->employeeNumber);
    }

    // The employee's name.
    property String^ Name
    {
        String^ get() { return name; }
        void set(String^ value) { name = value; }
    }

    // The employee's employee number.
    property int EmployeeNumber
    {
        int get() { return employeeNumber; }
        void set(int value) { employeeNumber = value; }
    }

private:
    String^ name;
    int employeeNumber;
};

int main()
{
    // Create a new employee object.
    Employee empl1419;
    empl1419.Name = L"Darin Lockert";
    empl1419.EmployeeNumber = 1419;

    // Add the employee to the set of all employees.
    set<Employee>^ emplSet = gcnew set<Employee>();
    emplSet->insert(empl1419);

    // List all employees of the company.
    for each (Employee^ empl in emplSet)
    {
        Console::WriteLine("Employee Number {0}: {1}",
            empl->EmployeeNumber, empl->Name);
    }

    return 0;
}

Typy wartości bez skrzynki odbiorczej

Można również wstawić typ wartości bez skrzynki odbiorczej do kontenera STL/CLR. Typ wartości bez skrzynki odbiorczej jest typem wartości, który nie został w polu typu odwołania.

Element typu wartości może być jednym z typów wartości standardowych, takich jak int, lub może być typem wartości zdefiniowanej przez użytkownika, takim jak value class. Aby uzyskać więcej informacji, zobacz Klasy i struktury

Przykład

Poniższy przykład modyfikuje pierwszy przykład, tworząc klasę Employee jako typ wartości. Ten typ wartości jest następnie wstawiany do cliext::set elementu tak samo jak w pierwszym przykładzie.

// cliext_container_valid_valuetype.cpp
// compile with: /clr

#include <cliext/set>

using namespace cliext;
using namespace System;

value class Employee
{
public:
    // Associative containers such as maps and sets
    // require a comparison operator to be defined
    // to determine proper ordering.
    bool operator<(const Employee^ rhs)
    {
        return (employeeNumber < rhs->employeeNumber);
    }

    // The employee's name.
    property String^ Name
    {
        String^ get() { return name; }
        void set(String^ value) { name = value; }
    }

    // The employee's employee number.
    property int EmployeeNumber
    {
        int get() { return employeeNumber; }
        void set(int value) { employeeNumber = value; }
    }

private:
    String^ name;
    int employeeNumber;
};

int main()
{
    // Create a new employee object.
    Employee empl1419;
    empl1419.Name = L"Darin Lockert";
    empl1419.EmployeeNumber = 1419;

    // Add the employee to the set of all employees.
    set<Employee>^ emplSet = gcnew set<Employee>();
    emplSet->insert(empl1419);

    // List all employees of the company.
    for each (Employee empl in emplSet)
    {
        Console::WriteLine("Employee Number {0}: {1}",
            empl.EmployeeNumber, empl.Name);
    }

    return 0;
}

Jeśli spróbujesz wstawić uchwyt do typu wartości w kontenerze, zostanie wygenerowany błąd kompilatora C3225 .

Implikacje dotyczące wydajności i pamięci

Podczas określania, czy należy używać dojść do odwołań do typów lub typów wartości jako elementów kontenera, należy wziąć pod uwagę kilka czynników. Jeśli zdecydujesz się używać typów wartości, pamiętaj, że kopia elementu jest wykonana za każdym razem, gdy element zostanie wstawiony do kontenera. W przypadku małych obiektów nie powinno to stanowić problemu, ale jeśli wstawione obiekty są duże, wydajność może być mniejsza. Ponadto, jeśli używasz typów wartości, nie można przechowywać jednego elementu w wielu kontenerach jednocześnie, ponieważ każdy kontener będzie miał własną kopię elementu.

Jeśli zdecydujesz się użyć uchwytów do typów referencyjnych, wydajność może wzrosnąć, ponieważ nie jest konieczne utworzenie kopii elementu podczas wstawiania go do kontenera. Ponadto, w przeciwieństwie do typów wartości, ten sam element może istnieć w wielu kontenerach. Jeśli jednak zdecydujesz się na użycie dojść, należy zadbać o to, aby upewnić się, że uchwyt jest prawidłowy i że obiekt, do którego się odwołuje, nie został usunięty w innym miejscu w programie.

Problemy z własnością kontenerów

Kontenery w STL/CLR działają na semantyce wartości. Za każdym razem, gdy wstawisz element do kontenera, wstawiona jest kopia tego elementu. Jeśli chcesz uzyskać semantyka przypominającą odwołanie, możesz wstawić uchwyt do obiektu, a nie sam obiekt.

Podczas wywoływania metody czyszczenia lub wymazania kontenera obiektów dojścia obiekty obiekty, do których odwołują się uchwyty, nie są zwalniane z pamięci. Należy jawnie usunąć obiekt lub, ponieważ te obiekty znajdują się na zarządzanym stercie, zezwalaj modułowi odśmiecającego pamięć, gdy ustali, że obiekt nie jest już używany.

Zobacz też

Dokumentacja standardowej biblioteki C++