共用方式為


STL/CLR 容器

STL/CLR 程式庫有 Standard C++ 程式庫中可找到的相同容器,不過它是執行在 .NET Framework 中的 Managed 環境。 如果您已熟悉 Standard Template Library (STL), STL/CLR 是您繼續使用在升級程式碼至 Common Language Runtime (CLR) 時已熟悉的技巧之最佳方法。

文件提供了 STL/CLR 容器的概觀,例如容器項目的需求、您可以插入的容器項目的型別,以及容器中項目的擁有權發行。 其中提到原生標準樣板程式庫和 STL/CLR 之間的差異。

容器項目的需求

所有插入至 STL 容器的項目必須遵守某些方針。 如需詳細資訊,請參閱STL/CLR 容器項目的需求

有效的容器項目

STL/CLR 容器可保留兩種型別之一的項目:

  • 參考型別的控制代碼。

  • 參考型別。

  • Unboxed 實值型別。

您不能插入 Boxed 實值型別至任何 STL/CLR 容器。

參考型別的控制代碼。

您可以插入參考型別的控制代碼至 STL/CLR 容器。 C++ 中以 CLR 為目標的控制代碼是類似於原生 C++ 的指標。 如需詳細資訊,請參閱物件控制代碼運算子 (^) (C++ 元件擴充功能)

範例

下列範例示範如何將 Employee 物件的控制代碼插入至 cliext::set

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

#include <cliext/set>

using namespace cliext;
using namespace System;

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

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

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

        return *this;
    }

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

參考類型

參考型別 (而不是參考型別的控制代碼) 也可以插入至 STL/CLR 容器。 這裡的主要差異在於,當參考型別的容器被刪除時,會呼叫容器所有項目的解構函式。 在參考型別的控制代碼的容器,這些項目的解構函式將不會被呼叫。

範例

下列範例示範如何插入 Employee 物件至 cliext::set 內。

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

#include <cliext/set>

using namespace cliext;
using namespace System;

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

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

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

        return *this;
    }

    // All STL 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 實值型別

您也可以插入 Unboxed 實值型別至 STL/CLR 容器。 Unboxed 實值型別是尚未被 boxed 至參考型別的實值型別。

實值型別元素可以是其中一個標準實值型別,例如 int,也可以是使用者定義的實值型別,例如 value class。 如需詳細資訊,請參閱類別和結構 (C++ 元件擴充功能)

範例

下列範例會修改第一個範例,將 Employee 類別改為實值型別。 這個實值型別接著會插入至 cliext::set ,就如第一個範例中所示。

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

如果您嘗試插入實值型別的控制代碼到容器,會產生 編譯器錯誤 C3225

效能和記憶體含意

在決定使用參考型別的控制代碼或實值型別作為容器項目時,您必須考量許多因素。 如果您決定使用實值型別,請確定每次將項目插入至容器,產生這個項目的複本。 若為小型物件,這應該不會造成問題,但是如果插入物件很大,效能可能會減損。 此外,如果您使用實值型別,同時儲存一個項目在多個容器是不可能的,因為每個容器將會擁有其項目的複本。

如果您決定使用參考型別的控制代碼,效能可能會增加,因為在容器中插入時不需要製作項目的複本。 此外,不同於與實值型別,同一個項目可以存在於多個容器。 不過,如果您決定使用控制代碼,您必須小心確保控制代碼有效,並且它所參考的物件沒有在程式中的其他地方被刪除。

容器的所有權限問題

STL/CLR 的容器影響實值語意。 每當您插入項目至容器時,也會插入該項目的複本。 如果您要取得類似參考的語意,您可以插入物件的控制代碼物件而不是物件本身。

當您呼叫控制代碼物件的容器之清除或清理方法時,控制代碼所參考的物件不會從記憶體被釋放。 您必須明確地刪除物件,或者 (因為這些物件在 Managed 堆積中) 允許記憶體回收,以便一旦決定不再使用物件時,可以釋放記憶體。

請參閱

參考

標準樣板程式庫