STL/CLR-Container

Die STL/CLR-Bibliothek besteht aus Containern, die denen in der C++-Standardbibliothek ähneln, aber in der verwalteten Umgebung von .NET Framework ausgeführt werden. Sie wird nicht mit der tatsächlichen C++-Standardbibliothek auf dem neuesten Stand gehalten und wird für die Legacyunterstützung beibehalten.

Dieses Dokument bietet eine Übersicht über die Container in STL/CLR, z. B. die Anforderungen für Containerelemente, die Typen von Elementen, die Sie in die Container einfügen können, und Besitzerprobleme mit den Elementen in den Containern. Gegebenenfalls werden Unterschiede zwischen der systemeigenen C++-Standardbibliothek und STL/CLR erwähnt.

Anforderungen für Containerelemente

Alle in STL/CLR-Containern eingefügten Elemente müssen bestimmten Richtlinien entsprechen. Weitere Informationen finden Sie unter "Requirements for STL/CLR Container Elements".

Gültige Containerelemente

STL/CLR-Container können einen von zwei Arten von Elementen enthalten:

  • Ziehpunkte für Verweistypen.

  • Verweistypen.

  • Unboxed value types.

Sie können boxed value types nicht in einen der STL/CLR-Container einfügen.

Handles für Verweistypen

Sie können einen Handle in einen Verweistyp in einen STL/CLR-Container einfügen. Ein Handle in C++, das auf die CLR ausgerichtet ist, entspricht einem Zeiger in systemeigenem C++. Weitere Informationen finden Sie unter Handle to Object Operator (^).

Beispiel

Das folgende Beispiel zeigt, wie Sie ein Handle in ein Employee-Objekt in eine cliext::set einfügen.

// 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;
}

Verweistypen

Es ist auch möglich, einen Verweistyp (anstelle eines Handles für einen Verweistyp) in einen STL/CLR-Container einzufügen. Der Hauptunterschied besteht darin, dass beim Löschen eines Containers mit Verweistypen der Destruktor für alle Elemente innerhalb dieses Containers aufgerufen wird. In einem Container mit Handles für Verweistypen würden die Destruktoren für diese Elemente nicht aufgerufen.

Beispiel

Das folgende Beispiel zeigt, wie sie ein Employee-Objekt in ein 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;
}

Unboxed Value Types

Sie können auch einen unboxierten Werttyp in einen STL/CLR-Container einfügen. Ein unboxter Werttyp ist ein Werttyp, der nicht in einen Bezugstyp eingeboxt wurde.

Ein Werttypelement kann eines der Standardwerttypen sein, z. B. ein intWerttyp oder ein benutzerdefinierter Werttyp, z. B. ein value class. Weitere Informationen finden Sie unter Klassen und Strukturen

Beispiel

Im folgenden Beispiel wird das erste Beispiel geändert, indem die Employee-Klasse als Werttyp festgelegt wird. Dieser Werttyp wird dann wie im ersten Beispiel in ein cliext::set beispiel eingefügt.

// 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;
}

Wenn Sie versuchen, ein Handle in einen Werttyp in einen Container einzufügen, wird Compilerfehler C3225 generiert.

Leistungs- und Speicherauswirkungen

Sie müssen mehrere Faktoren berücksichtigen, wenn Sie bestimmen, ob Handles zum Verweisen auf Typen oder Werttypen als Containerelemente verwendet werden sollen. Wenn Sie werttypen verwenden möchten, denken Sie daran, dass jedes Mal, wenn ein Element in den Container eingefügt wird, eine Kopie des Elements erstellt wird. Bei kleinen Objekten sollte dies kein Problem sein, aber wenn die eingefügten Objekte groß sind, kann die Leistung beeinträchtigt werden. Wenn Sie Werttypen verwenden, ist es auch unmöglich, ein Element in mehreren Containern gleichzeitig zu speichern, da jeder Container über eine eigene Kopie des Elements verfügt.

Wenn Sie stattdessen Handles verwenden, um auf Typen zu verweisen, kann sich die Leistung erhöhen, da es nicht erforderlich ist, eine Kopie des Elements zu erstellen, wenn es in den Container eingefügt wird. Im Gegensatz zu Werttypen kann dasselbe Element auch in mehreren Containern vorhanden sein. Wenn Sie sich jedoch für die Verwendung von Handles entscheiden, müssen Sie sicherstellen, dass der Handle gültig ist und dass das Objekt, auf das es verweist, nicht an anderer Stelle im Programm gelöscht wurde.

Besitzprobleme mit Containern

Container in STL/CLR arbeiten an der Wertsemantik. Jedes Mal, wenn Sie ein Element in einen Container einfügen, wird eine Kopie dieses Elements eingefügt. Wenn Sie referenzähnliche Semantik abrufen möchten, können Sie anstelle des Objekts selbst ein Handle in ein Objekt einfügen.

Wenn Sie die Clear- oder Erase-Methode eines Containers mit Handle-Objekten aufrufen, werden die Objekte, auf die sich die Handles beziehen, nicht aus dem Arbeitsspeicher freigegeben. Sie müssen das Objekt entweder explizit löschen oder, da sich diese Objekte im verwalteten Heap befinden, zulassen, dass der Garbage Collector den Speicher freigibt, sobald es bestimmt, dass das Objekt nicht mehr verwendet wird.

Siehe auch

C++-Standardbibliotheksreferenz