C++/CLI Referenční příručka
Visual Studio 2022+ .NET / .NET Framework ISO C++ + CLR

01 Co je C++/CLI

C++/CLI (C++ for the Common Language Infrastructure) je rozšíření standardního C++ umožňující tvorbu spravovaného kódu pro CLR (.NET runtime). Kombinuje nativní C++ výkon s přístupem k celé .NET knihovně.

Klíčové vlastnosti
  • Přímý přístup k .NET Base Class Library (BCL)
  • Interoperabilita s existujícím nativním C/C++ kódem (It Just Works – IJW)
  • Garbage collector CLR spravuje spravované objekty; nativní paměť stále manuálně
  • Jeden soubor může mít managed i unmanaged kód současně
  • Kompilátor: MSVC s přepínačem /clr nebo /clr:pure
C++/CLI – hello world
#include <iostream>
using namespace System;

int main()
{
    // Spravovaný výstup (.NET)
    Console::WriteLine("Ahoj z .NET!");

    // Nativní výstup (C++)
    std::cout << "Ahoj z native C++!" << std::endl;

    return 0;
}
Ekvivalent v C#
using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Ahoj z .NET!");
        // Nativní kód není přímo přístupný
    }
}
Přepínač kompilátoru Popis
/clrSmíšený kód (native + managed) – nejběžnější pro interop
/clr:purePouze IL (spravovaný), ale může volat nativní DLL
/clr:safeČistě verifikovatelný IL (omezené možnosti)
/clr:netcoreCílí na .NET Core / .NET 5+ (VS 2019 16.4+)

02 Projekt a kompilace

Vytvoření projektu ve Visual Studiu

Nový projekt → CLR Empty Project nebo CLR Class Library. V Properties projektu ověřit: Configuration Properties → General → Common Language Runtime Support → /clr.

Struktura .vcxproj pro C++/CLI

Klíčová nastavení .vcxproj
<!-- Ve skupině PropertyGroup -->
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>

<!-- RuntimeLibrary musí být /MD nebo /MDd (ne /MT) -->
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

Podmíněný managed / unmanaged kód

Přepínání kontextu v jednom souboru
#pragma managed
ref class SpravovanaTrida {
    void MetodaCLR() { Console::WriteLine("CLR"); }
};

#pragma unmanaged
void NativniFunkce() {
    printf("Native\n");  // čistý C++
}

#pragma managed
// zbytek souboru opět managed
Při /clr nelze použít /MT (statický CRT). Vždy /MD nebo /MDd.

03 Typy a handles

C++/CLI zavádí nové operátory a modifikátory pro práci se spravovanou pamětí.

SyntaxePopisAnalogie
T^ Handle – spravovaný ukazatel (GC sleduje)C# T t (reference type)
T% Tracking reference – reference na spravovaný objektC# ref T
T* Nativní ukazatel (nespravovaný)C++ T*
gcnew Alokace na spravované haldě (GC heap)C# new
new Nativní alokace (C++ heap, manuální delete)C++ new
interior_ptr<T>Ukazatel uvnitř spravovaného objektuC# fixed (T* p = ...)
pin_ptr<T>Fixace spravovaného objektu v paměti (zabrání GC přesunu)C# fixed
safe_cast<T^>Bezpečný přetypovací operátor pro CLR typyC# as / (T)
nullptrNulová hodnota pro handle i nativní ukazatelC# null
Typy a handles – příklady
using namespace System;

// Handle na spravovaný objekt
String^ s = "Ahoj";                 // GC spravuje
String^ s2 = gcnew String("světe");

// Nativní ukazatel (manuální správa)
int* nativePtr = new int(42);
delete nativePtr;               // nutno uvolnit

// Tracking reference
void Uprav(String% text) {
    text = "Změněno";           // modifikuje originál
}

// Safe cast
Object^ obj = "text";
String^ str = safe_cast<String^>(obj);

// Dynamic cast (vrací nullptr při selhání)
String^ strOrNull = dynamic_cast<String^>(obj);
if (strOrNull != nullptr)
    Console::WriteLine(strOrNull);

Hodnotové vs referenční typy

KategorieC++/CLI syntaxeHaldaGC
Spravovaný ref typ ref class, ref struct GC heap ✅
Hodnotový typ (CLR) value class, value structStack / inline⚠️ boxing
Rozhraní interface class — —
Výčet enum class Stack ❌
Nativní třída class / struct C++ heap / stack❌

04 Spravovaná paměť a GC

IDisposable – destruktor a finalizer
ref class Zdroj {
public:
    // Destruktor → IDisposable::Dispose()
    ~Zdroj() {
        Console::WriteLine("Dispose");
        // uvolnit spravované zdroje
    }

    // Finalizer → Finalize() – volá GC
    !Zdroj() {
        Console::WriteLine("Finalize");
        // uvolnit NATIVNÍ zdroje
    }
};

// Automatické volání Dispose (jako C# using)
{
    Zdroj z;   // stack-like syntax → Dispose při opuštění bloku
    // ...
}  // z.Dispose() voláno zde

// Alternativa: explicitní delete
Zdroj^ zh = gcnew Zdroj();
delete zh;  // volá Dispose, nenavrátí paměť GC ihned
GC API
using namespace System;

// Vynutit GC kolekci (jen pro testování)
GC::Collect();
GC::WaitForPendingFinalizers();

// Potlačit finalizer (objekt je explicitně dispose-ován)
GC::SuppressFinalize(obj);

// Paměťový tlak (hlásit GC nativní alokace)
GC::AddMemoryPressure(1024 * 1024);
GC::RemoveMemoryPressure(1024 * 1024);
Stack-sémantika (Zdroj z; místo Zdroj^ z = gcnew Zdroj();) je preferovaný způsob – kompilátor automaticky vloží volání Dispose na konci bloku.

05 ref class / value class

ref class – plná CLR třída
using namespace System;

ref class Osoba {
private:
    String^ _jmeno;
    int _vek;

public:
    // Konstruktor
    Osoba(String^ jmeno, int vek)
        : _jmeno(jmeno), _vek(vek) {}

    // Property (automatická)
    property String^ Jmeno {
        String^ get() { return _jmeno; }
        void set(String^ v) { _jmeno = v; }
    }

    // Triviální property (auto-implementovaná)
    property int Vek;

    // Metoda
    virtual String^ ToString() override {
        return String::Format("{0}, {1} let", _jmeno, _vek);
    }

    // Statický člen
    static int Pocet = 0;
};
value class – hodnotový typ
// Jako C# struct – kopíruje se, neřídí GC
value class Bod {
public:
    double X, Y;

    Bod(double x, double y) : X(x), Y(y) {}

    double Vzdalenost(Bod jiny) {
        double dx = X - jiny.X, dy = Y - jiny.Y;
        return Math::Sqrt(dx*dx + dy*dy);
    }

    virtual String^ ToString() override {
        return String::Format("({0}, {1})", X, Y);
    }
};

// Použití
Bod b1(0.0, 0.0);
Bod b2(3.0, 4.0);
Console::WriteLine(b1.Vzdalenost(b2));  // 5

// Boxing (value → Object^)
Object^ boxed = b1;
Bod unboxed = safe_cast<Bod>(boxed);
enum class (CLR enum)
enum class Smer { Sever, Jih, Vychod, Zapad };
enum class Rezim : unsigned char { A = 1, B = 2, C = 4 };

Smer s = Smer::Sever;
if (s == Smer::Sever)
    Console::WriteLine("Na sever");

06 Dědičnost a rozhraní

Dědičnost
ref class Tvar {
public:
    virtual double Plocha() = 0;  // čistě virtuální
    virtual String^ Popis() { return "Tvar"; }
};

ref class Kruh : public Tvar {
public:
    property double Polomer;

    Kruh(double r) { Polomer = r; }

    virtual double Plocha() override {
        return Math::PI * Polomer * Polomer;
    }

    virtual String^ Popis() override {
        return "Kruh r=" + Polomer;
    }
};

// Sealed (zapečetěná třída – nelze dědit)
ref class ZapecetenaTrida sealed : Tvar {
    virtual double Plocha() override sealed { return 0; }
};
interface class
interface class IUlozitelny {
    void Uloz(String^ cesta);
    String^ Nacti(String^ cesta);
};

interface class ITiskovatelny {
    void Tiskni();
};

// Třída implementující více rozhraní
ref class Dokument : IUlozitelny, ITiskovatelny {
public:
    virtual void Uloz(String^ cesta) { /* ... */ }
    virtual String^ Nacti(String^ cesta) { return ""; }
    virtual void Tiskni() { /* ... */ }
};
Vícenásobná dědičnost je povolena pouze přes rozhraní (interface class), ne přes ref class. Jedna ref class může mít nejvýše jednoho spravovaného předka.

07 Properties a události

Typy properties
ref class Priklad {
private:
    int _hodnota;

public:
    // 1. Triviální (auto-implemented)
    property String^ Nazev;   // backing field automaticky

    // 2. Plná property
    property int Hodnota {
        int get()       { return _hodnota; }
        void set(int v) {
            if (v < 0) throw gcnew ArgumentOutOfRangeException();
            _hodnota = v;
        }
    }

    // 3. Read-only property
    property bool JeKladna {
        bool get() { return _hodnota > 0; }
    }

    // 4. Indexer (default indexed property)
    property String^ default[int] {
        String^ get(int i)            { return i.ToString(); }
        void    set(int i, String^ v) { /* ... */ }
    }

    // 5. Statická property
    static property int GlobalniPocet;
};
Události (events)
using namespace System;

// Delegát pro událost
delegate void ZmenaHodnotyHandler(Object^ sender, int novaHodnota);

ref class Sensor {
public:
    // Deklarace události
    event ZmenaHodnotyHandler^ ZmenaHodnoty;

    void NastavHodnotu(int v) {
        hodnota = v;
        // Vyvolat událost (zkontrolovat nullptr)
        ZmenaHodnoty(this, v);
    }

private:
    int hodnota;
};

// Přihlášení k události
Sensor^ s = gcnew Sensor();
s->ZmenaHodnoty += gcnew ZmenaHodnotyHandler(
    [](Object^ sender, int v) {
        Console::WriteLine("Nová hodnota: {0}", v);
    }
);

08 Generika (Generics)

Generická třída
generic<typename T>
ref class Zasobnik {
    Collections::Generic::List<T>^ data
        = gcnew Collections::Generic::List<T>();
public:
    void Push(T item) { data->Add(item); }
    T    Pop()        {
        int i = data->Count - 1;
        T v = data[i]; data->RemoveAt(i);
        return v;
    }
    property int Pocet { int get() { return data->Count; } }
};

// Použití
Zasobnik<int>^ z = gcnew Zasobnik<int>();
z->Push(1); z->Push(2);
Console::WriteLine(z->Pop());  // 2
Constraints (omezení)
generic<typename T>
where T : IComparable
T Maximum(T a, T b) {
    return (a->CompareTo(b) >= 0) ? a : b;
}

// where T : ref class (musí být ref typ)
generic<typename T>
where T : ref class, ICloneable
ref class KlonovatelnyKontejner { /* ... */ };

// where T : value class
generic<typename T>
where T : value class
void TiskniHodnotu(T val) {
    Console::WriteLine(val);
}
C++/CLI generic ≠ C++ template. Generika jsou runtime (CLR), templates jsou compile-time. Nelze kombinovat template<T> s managed typy v generickém kontextu.

09 Native ↔ Managed interop

Volání nativní funkce ze spravovaného kódu
#pragma unmanaged
int NativniVypocet(int a, int b) {
    return a * b + 42;   // čistý C++
}

#pragma managed
void SpravovanaFunkce() {
    int vysledek = NativniVypocet(5, 3);  // přímé volání
    Console::WriteLine(vysledek);
}
Nativní objekt uvnitř spravované třídy
#include <memory>

// Nativní třída (C++)
#pragma unmanaged
class NativniEngine {
public:
    void Spust() { printf("Engine bezi\n"); }
};

#pragma managed
ref class SpravovanyWrapper {
    NativniEngine* engine;  // nativní ukazatel
public:
    SpravovanyWrapper() {
        engine = new NativniEngine();
    }
    ~SpravovanyWrapper()  { delete engine; engine = nullptr; }
    !SpravovanyWrapper()  { delete engine; engine = nullptr; }

    void Spust() {
        if (engine) engine->Spust();
    }
};
Nikdy neuchovávejte handle (T^) v nativním kódu bez gcroot<T^> – GC může objekt přesunout nebo uvolnit!
gcroot – uložení handle v nativní třídě
#include <vcclr.h>   // pro gcroot

#pragma unmanaged
class NativeCallback {
public:
    // gcroot pin-uje GC handle
    gcroot<System::String^> message;

    void Tiskni() {
        // přechod zpět do managed – nutno #pragma managed volání
    }
};

10 Marshaling řetězců

String^ ↔ std::string / wstring / char*
#include <msclr/marshal_cppstd.h>
#include <msclr/marshal.h>
using namespace System;
using namespace msclr::interop;

// String^ → std::string
String^ ms = "Ahoj světe";
std::string ss = marshal_as<std::string>(ms);

// String^ → std::wstring
std::wstring ws = marshal_as<std::wstring>(ms);

// String^ → const char* (marshal_context potřeba!)
marshal_context ctx;
const char* cp = ctx.marshal_as<const char*>(ms);
// cp platí po dobu životnosti ctx

// std::string → String^
std::string s2 = "native";
String^ ms2 = marshal_as<String^>(s2);

// const char* → String^ (bez marshal_context)
const char* cstr = "text";
String^ ms3 = marshal_as<String^>(cstr);

// Alternativa: přímá konverze
String^ ms4 = gcnew String(cstr);        // char* → String^
String^ ms5 = gcnew String(L"wide");      // wchar_t* → String^
Zdrojový typCílový typMetoda
String^ std::string marshal_as<std::string>(s)
String^ std::wstring marshal_as<std::wstring>(s)
String^ const char* ctx.marshal_as<const char*>(s)
String^ const wchar_t* ctx.marshal_as<const wchar_t*>(s)
std::string String^ marshal_as<String^>(s)
std::wstring String^ marshal_as<String^>(s)
const char* String^ gcnew String(ptr)
const wchar_t* String^ gcnew String(wptr)

11 P/Invoke vs IJW

MechanismusPopisKdy použít
IJW (It Just Works) Přímé volání nativní DLL / .lib z C++/CLI – kompilátor vloží stub automaticky Existující C/C++ .lib nebo .dll + dostupné hlavičkové soubory
P/Invoke Deklarace nativní funkce přes [DllImport] atribut – marshaling hodnot Win32 API, externí DLL bez .lib, i z C#
COM Interop Import typové knihovny #import "lib.tlb" COM servery, ActiveX, Office automation
IJW – přímé linkování
// mylib.h + mylib.lib přidány do projektu
#include "mylib.h"
#pragma comment(lib, "mylib.lib")

#pragma managed
void VyuzijNativni() {
    // přímé volání – žádný Declare, žádný DllImport
    int r = nativni_funkce_z_lib(10, 20);
    Console::WriteLine(r);
}

12 P/Invoke – praktické příklady

Win32 MessageBox a GetTickCount
using namespace System::Runtime::InteropServices;

[DllImport("user32.dll", CharSet=CharSet::Unicode)]
extern "C" int MessageBoxW(IntPtr hWnd, String^ text,
                             String^ caption, unsigned int type);

[DllImport("kernel32.dll")]
extern "C" unsigned long GetTickCount();

// Volání
MessageBoxW(IntPtr::Zero, "Ahoj!", "Test", 0);
unsigned long ticks = GetTickCount();
Struktura jako P/Invoke parametr
using namespace System::Runtime::InteropServices;

[StructLayout(LayoutKind::Sequential)]
value struct SYSTEMTIME {
    unsigned short wYear, wMonth, wDayOfWeek, wDay;
    unsigned short wHour, wMinute, wSecond, wMilliseconds;
};

[DllImport("kernel32.dll")]
extern "C" void GetSystemTime(SYSTEMTIME% st);

SYSTEMTIME st;
GetSystemTime(st);
Console::WriteLine("{0}/{1}/{2}", st.wDay, st.wMonth, st.wYear);
Callback (function pointer → delegate)
using namespace System::Runtime::InteropServices;

delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll")]
extern "C" bool EnumWindows(EnumWindowsProc^ callback, IntPtr lParam);

// Delegate jako callback
EnumWindowsProc^ cb = gcnew EnumWindowsProc(
    [](IntPtr hWnd, IntPtr) -> bool {
        Console::WriteLine("okno: {0:X}", hWnd.ToInt64());
        return true;
    });
EnumWindows(cb, IntPtr::Zero);

13 .NET kolekce a STL.NET

System::Collections::Generic
using namespace System;
using namespace System::Collections::Generic;

// List<T>
List<int>^ list = gcnew List<int>();
list->Add(1); list->Add(2); list->Add(3);
for each (int x in list) Console::Write("{0} ", x);

// Dictionary<K,V>
Dictionary<String^, int>^ dict =
    gcnew Dictionary<String^, int>();
dict["jedna"] = 1;
dict["dva"]   = 2;
Console::WriteLine(dict["jedna"]);  // 1

// Stack<T> a Queue<T>
Stack<String^>^ zasobnik = gcnew Stack<String^>();
zasobnik->Push("A");
String^ top = zasobnik->Pop();

// HashSet<T>
HashSet<int>^ set = gcnew HashSet<int>();
set->Add(1); set->Add(1);
Console::WriteLine(set->Count);  // 1
for each (CLI range-for)
// Spravované kolekce
array<int>^ arr = { 10, 20, 30 };
for each (int x in arr)
    Console::WriteLine(x);

// Nativní std::vector – použijte C++11 range-for
std::vector<int> vec = {1, 2, 3};
for (int x : vec)
    printf("%d\n", x);

Spravovaná pole (array<T>^)

System::Array
// 1D pole
array<int>^ a = gcnew array<int>(5);
array<String^>^ names = { "A", "B", "C" };

// 2D pole
array<int, 2>^ mat = gcnew array<int, 2>(3, 3);
mat[0, 0] = 1;

// Řazení, kopírování
Array::Sort(a);
Array::Reverse(a);
Array::Copy(a, 0, b, 0, 5);

14 Výjimky

Zachycení CLR a nativních výjimek
using namespace System;

try {
    // Vyvolat spravovanou výjimku
    throw gcnew InvalidOperationException("Chyba!");
}
catch (InvalidOperationException^ ex) {
    Console::WriteLine("CLR chyba: {0}", ex->Message);
}
catch (Exception^ ex) {
    Console::WriteLine("Libovolná CLR: {0}", ex->Message);
}
catch (std::exception& e) {
    Console::WriteLine("Native STD: {0}", gcnew String(e.what()));
}
catch (...) {
    Console::WriteLine("Neznámá výjimka");
}
finally {
    Console::WriteLine("Vždy se spustí");
}

// Vlastní výjimka
ref class MojeVyjimka : Exception {
public:
    MojeVyjimka(String^ msg) : Exception(msg) {}
    MojeVyjimka(String^ msg, Exception^ inner)
        : Exception(msg, inner) {}
};
C++/CLI umí zachytit jak CLR výjimky (Exception^) tak nativní (std::exception&) v jednom try/catch bloku.

15 Delegáti a lambda

Delegáti a Func / Action
using namespace System;

// Vlastní delegát
delegate int Operace(int a, int b);

int Secti(int a, int b) { return a + b; }

// Přiřazení funkce
Operace^ op = gcnew Operace(Secti);
Console::WriteLine(op->Invoke(3, 4));  // 7

// Lambda (C++11 syntax, native lambda)
Operace^ lop = gcnew Operace(
    [](int a, int b) -> int { return a * b; }
);
Console::WriteLine(lop(3, 4));  // 12

// System::Func a System::Action
Func<int, int, int>^ f =
    gcnew Func<int, int, int>(Secti);

Action<String^>^ print =
    gcnew Action<String^>(
        [](String^ s){ Console::WriteLine(s); }
    );
print("Ahoj");

16 Vlákna a Task Parallel Library

Thread, Monitor, lock
using namespace System::Threading;

// Vytvoření vlákna
Thread^ t = gcnew Thread(
    gcnew ThreadStart([]() {
        Console::WriteLine("Vlákno: {0}",
            Thread::CurrentThread->ManagedThreadId);
    }));
t->Start();
t->Join();

// Mutex / Monitor
Object^ lockObj = gcnew Object();
Monitor::Enter(lockObj);
try {
    // kritická sekce
} finally {
    Monitor::Exit(lockObj);
}

// Interlocked operace
int pocitadlo = 0;
Interlocked::Increment(pocitadlo);
Interlocked::Add(pocitadlo, 5);
Task Parallel Library
using namespace System::Threading::Tasks;

// Task::Run
Task^ uloha = Task::Run(gcnew Action([](){
    Console::WriteLine("Async práce");
}));
uloha->Wait();

// Task s výsledkem
Task<int>^ vypocet = Task<int>::Run(
    gcnew Func<int>([]() -> int { return 42; })
);
int vysledek = vypocet->Result;

// Parallel::For
Parallel::For(0, 100, gcnew Action<int>(
    [](int i) { /* ... */ }
));

17 Unsafe kód a fixace paměti

pin_ptr – fixace GC objektu
#include <vcclr.h>

using namespace System;
using namespace System::Runtime::InteropServices;

// Fixace pole pro předání nativní funkci
array<unsigned char>^ data = gcnew array<unsigned char>(256);

pin_ptr<unsigned char> pinned = &data[0];
unsigned char* nativePtr = pinned;  // bezpečný nativní přístup
memset(nativePtr, 0xFF, 256);
// pinned vypadne ze scope → GC může opět přesouvat objekt

// Fixace String^ pro C API
String^ ms = "Testovací text";
pin_ptr<const wchar_t> wPin = PtrToStringChars(ms);
const wchar_t* wPtr = wPin;
wprintf(L"%s\n", wPtr);
interior_ptr – ukazatel uvnitř objektu
value struct Rect { int X, Y, W, H; };

Rect r = { 1, 2, 3, 4 };

// interior_ptr sleduje pohyb GC automaticky
interior_ptr<int> px = &r.X;
*px = 10;  // r.X = 10

// Iterace přes managed pole pomocí interior_ptr
array<int>^ arr = { 1, 2, 3 };
interior_ptr<int> p = &arr[0];
for (int i = 0; i < arr->Length; ++i, ++p)
    Console::Write(*p);

18 Atributy CLR

Použití a definice atributů
using namespace System;
using namespace System::Runtime::InteropServices;

// Standardní atributy
[Obsolete("Použijte NovouMetodu")]
void StaraMetoda() {}

[Serializable]
ref class Data {};

[DllImport("kernel32.dll", SetLastError=true)]
extern "C" bool CloseHandle(IntPtr h);

[StructLayout(LayoutKind::Explicit)]
value struct Union32 {
    [FieldOffset(0)] int   AsInt;
    [FieldOffset(0)] float AsFloat;
};

// Vlastní atribut
[AttributeUsage(AttributeTargets::Class)]
ref class AutorAttribute : Attribute {
public:
    property String^ Jmeno;
    AutorAttribute(String^ jmeno) { Jmeno = jmeno; }
};

[Autor("Pavel")]
ref class MojeTrida {};

19 Reflexe (Reflection)

Základy reflexe
using namespace System;
using namespace System::Reflection;

// Získat Type
Type^ t = String::typeid;              // compile-time
Type^ t2 = (gcnew String("x"))->GetType(); // runtime

// Výpis metod
array<MethodInfo^>^ methods = t->GetMethods();
for each (MethodInfo^ m in methods)
    Console::WriteLine(m->Name);

// Dynamické vytvoření instance
Object^ obj = Activator::CreateInstance(MojeTrida::typeid);

// Volání metody přes reflexi
MethodInfo^ mi = t->GetMethod("ToUpper");
Object^ res = mi->Invoke(gcnew String("ahoj"), nullptr);

// Čtení atributů
array<Object^>^ attrs =
    t->GetCustomAttributes(AutorAttribute::typeid, false);
for each (AutorAttribute^ a in attrs)
    Console::WriteLine("Autor: {0}", a->Jmeno);

20 Rychlá reference

Klíčová slova C++/CLI

ref class spravovaná třída (heap)
value class hodnotový typ (stack)
interface classCLR rozhraní
enum class CLR výčet
gcnew alokace na GC heap
delegate typově bezpečný callback
event CLR událost
property CLR vlastnost
generic CLR generikum
for each foreach pro CLR
nullptr null pro handle i ptr
sealed zapečetění třídy/metody
abstract abstraktní třída/metoda
literal compile-time konstanta
initonly pouze v konstruktoru

Operátory a typy

T^ handle (GC ref)
T% tracking reference
T* nativní ukazatel
@var adresa managed (ref)
*handle dereference handle
pin_ptr<T> fixace v GC heap
interior_ptrptr uvnitř GC obj
safe_cast bezpečné přetypování
T::typeid Type^ objektu
gcroot<T^> handle v native třídě

Frequently used namespaces

System Console, String, Math…
System::IO File, Stream, Path
Coll::Generic List, Dict, Stack
Threading Thread, Monitor, Task
Threading::Tasks Task, Parallel
Reflection Type, MethodInfo
Runtime::Interop DllImport, Marshal
Diagnostics Debug, Trace, Process
Text StringBuilder, Encoding
Net WebClient, HttpClient

Destruktor vs Finalizer

~ClassName()→ IDisposable::Dispose
!ClassName()→ Object::Finalize
Kdy volat ~managed resources
Kdy volat !native resources only
Stack syntaxauto Dispose na konci bloku
delete obj^volá Dispose (ne free)

Marshaling – rychlé tahy

String^ → char* marshal_context
String^ → wchar_t*PtrToStringChars
char* → String^ gcnew String(ptr)
std::string↔String^marshal_as<>
byte[] → byte* pin_ptr<byte>
struct v P/Invoke[StructLayout(Sequential)]

Common pitfalls

T^ v native použij gcroot<T^>
/MT s /clr NELZE – použij /MD
native λ → delegatelze, GC drží delegate
boxing valueObject^ = val → kopie
Dědičnost jen 1 ref base class
template+managednelze – použij generic
char* lifetimemarshal_context musí žít!

Kompilační přepínače (přehled)

PřepínačPopis
/clr Smíšený managed/native kód (nejčastější)
/clr:netcore Cílí .NET 5/6/7/8 (ne Framework)
/MD /MDd Dynamická CRT (povinná s /clr)
/W4 Úroveň varování 4 (doporučeno)
/GR RTTI – povoleno (výchozí s /clr)
/EHa Asynchronní výjimky (SEH + C++)
/fp:precise Přesná aritmetika plovoucí řádové čárky
/AI<dir> Přidat cestu k assembly referencím
/FU<file> Přidat using assembly (force using)