
std::unique_ptr<Handle, HandleDeleter> ); class ScopedResource { public: ScopedResource() = default; explicit ScopedResource(Resource resource) : resource_{ resource } {} ScopedResource(const ScopedResource&) = delete; ScopedResource& operator=(const ScopedResource&) = delete; ~ScopedResource() { DestroyResource(resource_); } operator const Resource&() const { return resource_; } private: Resource resource_{}; }; #include <memory> // From low-level API. using Handle = void*; Handle CreateHandle() { Handle h{ nullptr }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // error: expected argument of type void** ScopedHandle h{ CreateHandle() }; } ScopedHandle constructor expect an argument with type void** ? Recall that smart pointers were designed primarily for managing memory (that is, pointers): std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015). std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).std::unique_ptr int* . std::unique_ptr Handle* , void** . ? -, std::remove_pointer :
using ScopedHandle = std::unique_ptr<std::remove_pointer_t<Handle>, HandleDeleter>;
-, : pointer, :
struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>;
, , : Handle . Handle ; Handle – , .
, :
#include <memory> using Handle = int; Handle CreateHandle() { Handle h{ -1 }; /*...*/ return h; } void CloseHandle(Handle h) { /* ... */ } struct HandleDeleter { using pointer = Handle; void operator()(Handle h) { CloseHandle(h); } }; using ScopedHandle = std::unique_ptr<Handle, HandleDeleter>; int main() { // Error: type mismatch: "int" and "std::nullptr_t". ScopedHandle h{ CreateHandle() }; }
std::unique_ptr , , .
– NullablePointer Handle . , NullablePointer , , nullptr . Handle , int , . , std::unique_ptr , POSIX OpenGL.
, . Handle , NullablePointer, , , – .
, , «» . Bitmap :
// Graphics API. bool CreateBitmap(Bitmap* bmp) { /*...*/ return true; } bool DestroyBitmap(Bitmap bmp) { /* ... */ return true; } bool DrawBitmap(DeviceContext ctx, Bitmap bmp) { /* ... */ return true; } ... // User code. DeviceContext ctx{}; Bitmap bmp{}; CreateBitmap(&bmp); DrawBitmap(ctx, bmp);
Bitmap std::unique_ptr:
struct BitmapDeleter { using pointer = Bitmap; void operator()(Bitmap bmp) { DestroyBitmap(bmp); } }; using ScopedBitmap = std::unique_ptr<Bitmap, BitmapDeleter>; ... DeviceContext ctx{}; Bitmap tmp; CreateBitmap(&tmp); ScopedBitmap bmp{ tmp }; DrawBitmap(ctx, bmp.get());
, ScopedBitmap . , ScopedBitmap , Bitmap.
, – RAII-.
, . .
#include <cassert> #include <memory> // std::addressof template<typename ResourceTag, typename ResourceType> class Resource { public: Resource() noexcept = default; explicit Resource(ResourceType resource) noexcept : resource_{ resource } {} Resource(const Resource&) = delete; Resource& operator=(const Resource&) = delete; Resource(Resource&& other) noexcept : resource_{ other.resource_ } { other.resource_ = {}; } Resource& operator=(Resource&& other) noexcept { assert(this != std::addressof(other)); Cleanup(); resource_ = other.resource_; other.resource_ = {}; return *this; } ~Resource() { Cleanup(); } operator const ResourceType&() const noexcept { return resource_; } ResourceType* operator&() noexcept { Cleanup(); return &resource_; } private: // Intentionally undefined - must be explicitly specialized. void Cleanup() noexcept; ResourceType resource_{}; };
.
, , ( std::unique_ptr ). , ( std::shared_ptr ). , ResourceType (, void* int ), , noexcept . operator& – . , , - CreateHandle(Handle* handle) . -.
. , Cleanup , , . . , leanup , . :
// Here "FileId" is some OS-specific file descriptor type // which must be closed with CloseFile function. using File = Resource<struct FileIdTag, FileId>; template<> void File::Cleanup() noexcept { if (resource_) CloseFile(resource_); }
FileId :
{ File file{ CreateFile(file_path) }; ... } // "file" will be destroyed here
Cleanup Resource « ». , Cleanup FileId « » .
— ResourceTag?
- , ResourceTag ? .
-, . , void* . - :
using ScopedBitmap = Resource<Bitmap>; using ScopedTexture = Resource<Texture>; void DrawBitmap(DeviceContext& ctx, ScopedBitmap& bmp) { /* ... */ } int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; // Passing texture to function expecting bitmap. // Compiles OK. DrawBitmap(ctx, t); }
, :
using ScopedBitmap = Resource<struct BitmapTag, Bitmap>; using ScopedTexture = Resource<struct TextureTag, Texture>; int main() { DeviceContext ctx; ScopedBitmap bmp; ScopedTexture t; DrawBitmap(ctx, t); // error: type mismatch }
: Cleanup , C++ . , , Bitmap DestroyBitmap , Texture – DestroyTexture . , ScopedBitmap ScopedTexture (, Bitmap , Texture void* ), .
, :
using File = Resource<struct FileIdTag, FileId>;
, struct FileIdTag . , , :
struct FileIdTag{}; using File = Resource<FileIdTag, FileId>;
, . , . , . , . , C++ , :
struct FileIdTag; using File = Resource<FileIdTag, FileId>;
, , FileIdTag , :
using File = Resource<struct FileIdTag, FileId>;
…
Cleanup, / . . , :
, ( ) , ; . static_assert :
void Cleanup() noexcept { static_assert(false, "This function must be explicitly specialized."); }
, , : Cleanup . : static_assert , , , .
, : . , - , false:
static constexpr bool False() noexcept { return false; } void Cleanup() noexcept { static_assert(False(), "This function must be explicitly specialized."); }
RAII-, , , . - , , ‑ ? , , :
class Bitmap { public: Bitmap(int width, int height); ~Bitmap(); int Width() const; int Height() const; Colour PixelColour(int x, int y) const; void PixelColour(int x, int y, Colour colour); DC DeviceContext() const; /* Other methods... */ private: int width_{}; int height_{}; // Raw resources. BITMAP bitmap_{}; DC device_context_{}; };
, , Bitmap:
Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = CreateBitmap(width, height); if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = CreateCompatibleDc(); if (!device_context_) // bitmap_ will be leaked here! throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
, : ( Windows GDI , , , , ). : device_context_ , bitmap_ !
:
using ScopedBitmap = Resource<struct BitmapTag, BITMAP>; using ScopedDc = Resource<struct DcTag, DC>; ... Bitmap::Bitmap(int width, int height) : width_{ width }, height_{ height } { // Create bitmap. bitmap_ = ScopedBitmap{ CreateBitmap(width, height) }; if (!bitmap_) throw std::runtime_error{ "Failed to create bitmap." }; // Create device context. device_context_ = ScopedDc{ CreateCompatibleDc() }; if (!device_context_) // Safe: bitmap_ will be destroyed in case of // exception. throw std::runtime_error{ "Failed to create bitmap DC." }; // Select bitmap into device context. // ... }
: . RAII , . , ( ).
Windows API. Windows API, RAII ( ; Windows API ).
// Windows handle. using Handle = Resource<struct HandleTag, HANDLE>; template<> void Handle::Cleanup() noexcept { if (resource_ && resource_ != INVALID_HANDLE_VALUE) CloseHandle(resource_); } // WinInet handle. using InetHandle = Resource<struct InetHandleTag, HINTERNET>; template<> void InetHandle::Cleanup() noexcept { if (resource_) InternetCloseHandle(resource_); } // WinHttp handle. using HttpHandle = Resource<struct HttpHandleTag, HINTERNET>; template<> void HttpHandle::Cleanup() noexcept { if (resource_) WinHttpCloseHandle(resource_); } // Pointer to SID. using Psid = Resource<struct PsidTag, PSID>; template<> void Psid::Cleanup() noexcept { if (resource_) FreeSid(resource_); } // Network Management API string buffer. using NetApiString = Resource<struct NetApiStringTag, wchar_t*>; template<> void NetApiString::Cleanup() noexcept { if (resource_ && NetApiBufferFree(resource_) != NERR_Success) { // Log diagnostic message in case of error. } } // Certificate store handle. using CertStore = Resource<struct CertStoreTag, HCERTSTORE>; template<> void CertStore::Cleanup() noexcept { if (resource_) CertCloseStore(resource_, CERT_CLOSE_STORE_FORCE_FLAG); }
, :
, ( , Resource ); , , (inline): , – , .
unique_resource N3949
, , N3949 . N3949 unique_resource_t , , ( , std::unique_ptr ):
template<typename Resource, typename Deleter> class unique_resource_t { /* … */ }; // Factory. template<typename Resource, typename Deleter> unique_resource_t<Resource, Deleter> unique_resource(Resource&& r, Deleter d) noexcept { /* … */ } ... // Usage (predefined deleter). struct ResourceDeleter { void operator()(Resource resource) const noexcept { if (resource) DestroyResource(resource); } }; using ScopedResource = unique_resource_t<Resource, ResourceDeleter>; ScopedResource r{ CreateResource(), ResourceDeleter{} }; // Alternative usage (in-place deleter definition). auto r2 = unique_resource( CreateResource(), [](Resource r){ if (r) DestroyResource(r); });
, unique_resource_t , Resource – . , , ( , RAII-). , . , , .
, , , , , Windows API CertCloseStore, .
, , Resource unique_resource_t . , , (. ., operator() ). unique_resource_t , , , ( ).
, C++, .
RAII-, , , , . :
– ; , ; .
, , . , , . , , , . , .
.
: , Positive Technologies
126 Overload ( 2015).Source: https://habr.com/ru/post/255487/
All Articles