STL/CLR – kontejnery
Knihovna STL/CLR se skládá z kontejnerů podobných kontejnerům, které se nacházejí ve standardní knihovně C++, ale běží v rámci spravovaného prostředí rozhraní .NET Framework. Aktuální standardní knihovnu jazyka C++ se neudržuje a udržuje se pro podporu starší verze.
Tento dokument obsahuje přehled kontejnerů v STL/CLR, například požadavky na prvky kontejneru, typy prvků, které můžete vložit do kontejnerů, a problémy s vlastnictvím prvků v kontejnerech. V případě potřeby jsou uvedeny rozdíly mezi nativní standardní knihovnou C++ a STL/CLR.
Požadavky na elementy kontejneru
Všechny prvky vložené do kontejnerů STL/CLR musí dodržovat určité pokyny. Další informace najdete v tématu Požadavky na elementy kontejneru STL/CLR.
Platné elementy kontejneru
Kontejnery STL/CLR mohou obsahovat jeden ze dvou typů prvků:
Zpracovává odkazy na typy.
Odkazové typy.
Unboxed value types.
Do žádného kontejneru STL/CLR nelze vložit typy hodnot v rámečku.
Obslužné rutiny pro odkazové typy
Popisovač můžete vložit do typu odkazu do kontejneru STL/CLR. Popisovač v jazyce C++, který cílí na CLR, je podobný ukazateli v nativním jazyce C++. Další informace naleznete v tématu Popisovač objektu –^).
Příklad
Následující příklad ukazuje, jak vložit popisovač objektu Employee do 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/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 odkazů
Do kontejneru STL/CLR je také možné vložit odkazový typ (nikoli popisovač odkazového typu). Hlavní rozdíl je v tom, že při odstranění kontejneru odkazových typů se destruktor volá pro všechny prvky uvnitř tohoto kontejneru. V kontejneru popisovačů pro odkazové typy by se destruktory těchto prvků nevolaly.
Příklad
Následující příklad ukazuje, jak vložit Employee objekt do .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
Do kontejneru STL/CLR můžete také vložit rozbalený typ hodnoty. Unboxed value type is a value type that has not boxed into a reference type.
Prvek typu hodnoty může být jedním ze standardních hodnotových typů, jako int
je například , nebo může být uživatelem definovaný typ hodnoty, například value class
. Další informace naleznete v tématu Třídy a struktury
Příklad
Následující příklad upraví první příklad tak, že employee třída typ hodnoty. Tento typ hodnoty se pak vloží do stejné hodnoty cliext::set
jako v prvním příkladu.
// 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;
}
Pokud se pokusíte vložit popisovač do typu hodnoty do kontejneru, vygeneruje se chyba kompilátoru C3225 .
Dopad na výkon a paměť
Při určování, zda použít popisovače odkazující typy nebo typy hodnot jako elementy kontejneru, je třeba vzít v úvahu několik faktorů. Pokud se rozhodnete použít typy hodnot, mějte na paměti, že kopie prvku se vytvoří při každém vložení elementu do kontejneru. U malých objektů by to neměl být problém, ale pokud jsou vložené objekty velké, může dojít k snížení výkonu. Pokud používáte hodnotové typy, není také možné uložit jeden prvek do více kontejnerů najednou, protože každý kontejner by měl vlastní kopii prvku.
Pokud se rozhodnete místo toho použít popisovače pro odkazové typy, může se zvýšit výkon, protože při vložení do kontejneru není nutné vytvořit kopii prvku. Na rozdíl od hodnotových typů může stejný prvek existovat i ve více kontejnerech. Pokud se však rozhodnete použít popisovače, musíte se ujistit, že popisovač je platný a že objekt, na který odkazuje, nebyl odstraněn jinde v programu.
Problémy s vlastnictvím kontejnerů
Kontejnery v STL/CLR pracují na sémantice hodnot. Při každém vložení elementu do kontejneru se vloží kopie tohoto prvku. Pokud chcete získat sémantiku podobné referenci, můžete vložit popisovač do objektu, nikoli do samotného objektu.
Při volání vymazat nebo vymazat metodu kontejneru popisovač objektů, objekty, které popisovače odkazují, nejsou uvolněny z paměti. Objekt musíte buď explicitně odstranit, nebo, protože tyto objekty se nacházejí ve spravované haldě, povolte uvolňování paměti, jakmile zjistí, že se objekt už nepoužívá.