CodeNebula
C++23stlexpert

std::out_ptr / std::inout_ptr (C++23 Addition)

C++23 · Completing Modern · Compiler flag: -std=c++23

Explanation

Smart pointer adaptors for C APIs that write to an output pointer parameter (`T**`).

Real-World Scenario

Pass a `std::unique_ptr` to a C library function that allocates and returns a handle via output parameter.

Quick Snippet

snippet.cpp
std::unique_ptr<FILE, decltype(&fclose)> file(nullptr, &fclose);
c_api_open_file(std::out_ptr(file));

Full Example

out_ptr.cpp
// CodeNebula - C++23 Example: std::out_ptr
// Compile: g++ -std=c++23 -Wall -Wextra -o example out_ptr.cpp
// Note: Requires GCC 13+ / Clang 17+

#include <iostream>
#include <memory>

// std::out_ptr and std::inout_ptr adapt smart pointers for C-style APIs
// that take T** output parameters (e.g., create/get functions).

// Simulated C-style API: creates a resource, returns via out-parameter
struct CResource {
    int id;
    const char* name;
};

int c_create_resource(CResource** out, int id) {
    if (!out) return -1;
    *out = new CResource{id, "MyResource"};
    return 0;  // success
}

void c_free_resource(CResource* res) {
    delete res;
}

// Another C API: replaces an existing resource (inout pattern)
int c_replace_resource(CResource** inout, int new_id) {
    if (!inout) return -1;
    if (*inout) {
        c_free_resource(*inout);
    }
    *inout = new CResource{new_id, "ReplacedResource"};
    return 0;
}

// Custom deleter for unique_ptr
struct ResourceDeleter {
    void operator()(CResource* r) const {
        std::cout << "  Deleting resource id=" << r->id << "\n";
        c_free_resource(r);
    }
};

using ResourcePtr = std::unique_ptr<CResource, ResourceDeleter>;

int main() {
    std::cout << "=== std::out_ptr for C API interop ===\n\n";

    // --- std::out_ptr: acquire a new resource ---
    std::cout << "Creating resource with std::out_ptr:\n";
    ResourcePtr res;
    int err = c_create_resource(std::out_ptr(res), 42);
    if (err == 0) {
        std::cout << "  Resource created: id=" << res->id
                  << ", name=" << res->name << "\n";
    }

    // --- std::inout_ptr: replace an existing resource ---
    std::cout << "\nReplacing resource with std::inout_ptr:\n";
    err = c_replace_resource(std::inout_ptr(res), 99);
    if (err == 0) {
        std::cout << "  Resource replaced: id=" << res->id
                  << ", name=" << res->name << "\n";
    }

    // --- out_ptr with shared_ptr ---
    std::cout << "\nUsing out_ptr with shared_ptr:\n";
    std::shared_ptr<CResource> shared_res;
    err = c_create_resource(
        std::out_ptr(shared_res, ResourceDeleter{}), 77);
    if (err == 0) {
        std::cout << "  Shared resource: id=" << shared_res->id
                  << ", use_count=" << shared_res.use_count() << "\n";
    }

    std::cout << "\nResources cleaned up automatically on scope exit:\n";
    return 0;
}

// Expected output:
// === std::out_ptr for C API interop ===
//
// Creating resource with std::out_ptr:
//   Resource created: id=42, name=MyResource
//
// Replacing resource with std::inout_ptr:
//   Deleting resource id=42
//   Resource replaced: id=99, name=ReplacedResource
//
// Using out_ptr with shared_ptr:
//   Shared resource: id=77, use_count=1
//
// Resources cleaned up automatically on scope exit:
//   Deleting resource id=77
//   Deleting resource id=99
Run command
g++ -std=c++23 -Wall -Wextra -o example out_ptr.cpp