Контейнеры STL/CLR
Библиотека STL/CLR имеет те же контейнеров, которые находятся в стандартной библиотеке C++, но она выполняется в управляемую среду платформы .NET Framework.Если вы уже знакомы с библиотекой стандартных шаблонов (STL), то STL/CLR лучший способ продолжения использования навыки, которые уже начинали при обновлении код к целевому объекту среды CLR.
Этот документ содержит общие сведения о контейнеров STL/CLR, например требования для элементов-контейнеров, типов элементов, которые можно вставить в контейнеры и проблем владения с элементами в контейнерах.При необходимости, различия между собственным стандартной библиотекой шаблонов и STL/CLR упомяните.
Требования для элементов-контейнеров
Все элементы, вставляемые в контейнеров STL должны повиноваться некоторым рекомендациям.Дополнительные сведения см. в разделе Требования для элементов-контейнеров STL/CLR.
Допустимые элементы контейнера
Контейнеры STL/CLR могут содержать один из 2 типов элементов:
Маркеры к ссылочным типам.
Ссылочные типы.
Unboxed типы значений.
Нельзя вставить упакованные типы значения в любые контейнеры 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 тип значения является типом значения, который не был помещается в упакован в ссылочный тип.
Элемент типа значения может быть одним из стандартных типов значений, например int или определяемым пользователем типом значения, такие как value class.Дополнительные сведения см. в разделе Классы и структуры (расширения компонентов C++).
Пример
Следующий пример изменяет первый пример, выполнив классом сотрудника тип значения.Этот тип значения затем вставляется в 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 значения.Каждый раз при вставке элемента в контейнер копию этого элемента.Если необходимо получить ссылка-как семантика, можно ввести дескриптор объекта, а не сам объект.
При вызове или стираете метод clear контейнера объектов маркера, объекты, которые ссылаются на лексемы не будут освобождены из памяти.Необходимо явно удаления объекта или поскольку эти объекты находятся в управляемой куче, включите сборщик мусора освободить память, как только она определяет, что объект больше не используется.