{"id":22466768,"url":"https://github.com/skillfulelectro/empointer","last_synced_at":"2026-04-20T14:02:19.333Z","repository":{"id":250526726,"uuid":"834712386","full_name":"SkillfulElectro/EMPointer","owner":"SkillfulElectro","description":"safety first C/C++ programming","archived":false,"fork":false,"pushed_at":"2025-04-09T17:50:38.000Z","size":55,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-09T18:47:14.115Z","etag":null,"topics":["c","cpp","memory-allocation","memory-leak","memory-management","safety"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SkillfulElectro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-28T06:04:53.000Z","updated_at":"2025-04-09T17:50:42.000Z","dependencies_parsed_at":"2024-07-28T07:23:09.313Z","dependency_job_id":"9dc26cd7-c434-4d5c-b9da-0a1c1af1fc6b","html_url":"https://github.com/SkillfulElectro/EMPointer","commit_stats":null,"previous_names":["skillfulelectro/empointer"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SkillfulElectro/EMPointer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkillfulElectro%2FEMPointer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkillfulElectro%2FEMPointer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkillfulElectro%2FEMPointer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkillfulElectro%2FEMPointer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SkillfulElectro","download_url":"https://codeload.github.com/SkillfulElectro/EMPointer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkillfulElectro%2FEMPointer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32050451,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","cpp","memory-allocation","memory-leak","memory-management","safety"],"created_at":"2024-12-06T10:13:33.232Z","updated_at":"2026-04-20T14:02:19.324Z","avatar_url":"https://github.com/SkillfulElectro.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EMPointer\n\n## Goal\n\n`EMPointer` is a C++ header-only smart pointer designed to bring RAII (Resource Acquisition Is Initialization) and reference-counted shared ownership to dynamically allocated memory, while aiming to be as syntactically close to raw pointers (`T*`) as possible. The goal is to provide a safer alternative to manual memory management (`new`/`delete`/`delete[]`) with minimal code changes for basic operations.\n\n## Key Features\n\n*   **RAII:** Automatically manages the lifetime of dynamically allocated objects or arrays. Memory is released when the last `EMPointer` referencing it goes out of scope.\n*   **Shared Ownership:** Uses reference counting to allow multiple `EMPointer` instances to safely share ownership of the same resource.\n*   **Raw Pointer Syntax:** Overloads common operators (`*`, `-\u003e`, `[]`, comparisons, boolean conversion) to mimic raw pointer usage.\n*   **Pointer Arithmetic:** Supports pointer arithmetic operators (`++`, `--`, `+=`, `-=`, `+`, `-`), while ensuring correct deallocation by tracking the original allocation address.\n*   **Custom Deleters:** Allows providing custom cleanup logic (e.g., for C API resources like `FILE*` or memory from `malloc`) using `std::function`.\n*   **`void*` Specialization:** Provides basic support for managing `void*`.\n*   **Implicit Conversion:** Offers an implicit conversion to the underlying raw pointer type (`T*`) for easier interoperability with functions expecting raw pointers (use with caution).\n*   **Ownership Release:** Includes a `do_not_manage()` method to detach the smart pointer and release ownership, returning the raw pointer for manual management.\n\n## Differences from Raw Pointers \u0026 Handling\n\nWhile `EMPointer` mimics much raw pointer syntax, it's not a *completely* transparent drop-in replacement due to safety features and C++ limitations. Migrating code requires attention to these key differences:\n\n1.  **Array Allocation:**\n    *   **Difference:** You cannot initialize an `EMPointer` for an array using `em::pointer\u003cT\u003e ptr = new T[size];`. This syntax incorrectly uses the single-object constructor.\n    *   **Handling:** **Must** use the explicit size constructor: `em::pointer\u003cT\u003e ptr = em::pointer\u003cT\u003e(size);`. This ensures `EMPointer` knows to use `delete[]` during cleanup.\n\n2.  **Pointer Arithmetic:**\n    *   **Difference:** Arithmetic operators (`++`, `+=`, etc.) modify the *current* pointer (`value`) used by access operators (`*`, `-\u003e`, `[]`). However, `EMPointer` stores the `original_value` separately and uses *that* for deallocation (`delete`/`delete[]`/custom deleter).\n    *   **Handling:** Arithmetic is safe regarding *deallocation*. However, after performing arithmetic, ensure the *current* pointer (`value`) still points within the valid bounds of the allocated memory before using `*`, `-\u003e`, or `[]`.\n\n3.  **Passing to Functions Expecting Raw Pointers:**\n    *   **Difference:** `EMPointer\u003cT\u003e` provides an implicit conversion `operator T*()`. This allows passing it directly to functions like `void func(T* ptr);` via `func(my_em_pointer);`.\n    *   **Handling:** While convenient, this carries a risk: if the obtained raw pointer outlives the `EMPointer` object, it becomes a dangling pointer. For clarity or safety, consider explicitly using `func(my_em_pointer.get_raw_ptr());`.\n\n4.  **Manual Deletion:**\n    *   **Difference:** `EMPointer` handles deletion automatically.\n    *   **Handling:** **Must remove** all manual `delete ptr;` and `delete[] ptr;` calls for pointers managed by `EMPointer`. Failure to do so will result in double-free errors and crashes.\n\n5.  **Casting:**\n    *   **Difference:** C++ casting keywords (`static_cast`, `reinterpret_cast`, `const_cast`) cannot be overloaded for custom types like `EMPointer`.\n    *   **Handling:** Perform casts on the raw pointer obtained via `get_raw_ptr()` or the implicit conversion: `static_cast\u003cN*\u003e(my_em_pointer)` or `static_cast\u003cN*\u003e(my_em_pointer.get_raw_ptr())`.\n\n6.  **Copying Semantics:**\n    *   **Difference:** Copying an `EMPointer` (`em::pointer\u003cT\u003e p2 = p1;` or `p2 = p1;`) implements *shared ownership* by incrementing the reference count. Copying a raw pointer (`T* p2 = p1;`) creates a shallow copy (alias), leading to potential double-delete or dangling pointer issues.\n    *   **Handling:** Be aware that multiple `EMPointer` objects can validly point to and manage the same resource. The resource is only deleted when the *last* owning `EMPointer` is destroyed.\n\n## Roadmap \u0026 Drop-in Replacement Status\n\n**Goal:** To be a near drop-in replacement for `T*` for common dynamic allocation patterns, adding RAII and shared ownership safety.\n\n**Added Features for Compatibility:**\n\n*   RAII for `new`/`new[]` (via size constructor)\n*   Reference counting / Shared Ownership\n*   Overloaded `*`, `-\u003e`, `[]`\n*   Overloaded comparison operators (`==`, `!=`, `\u003c`, `\u003e`, `\u003c=`, `\u003e=`) vs `EMPointer` and `nullptr`\n*   Boolean context evaluation (`if(ptr)`)\n*   Implicit conversion `operator T*()`\n*   Pointer Arithmetic Operators (`++`, `--`, `+=`, `-=`, `+`, `-`) (with safe deletion)\n*   Custom Deleter Support (`std::function`)\n*   `void*` specialization\n*   `do_not_manage()` method\n\n**Limitations / Not a Fully Transparent Replacement:**\n\n*   **Array Allocation Syntax:** Requires `em::pointer\u003cT\u003e(size)`, cannot use `new T[]` directly in assignment/initialization.\n*   **Casting:** Requires getting the raw pointer first (`get_raw_ptr()` or implicit conversion) before using C++ cast keywords.\n*   **Manual Deletion:** Existing `delete`/`delete[]` calls **must** be removed.\n*   **Implicit Conversion Risk:** While convenient, implicit conversion to `T*` can lead to dangling pointers if not handled carefully.\n\n`EMPointer` significantly improves safety over raw pointers but requires specific syntax adjustments (especially for arrays) and removal of manual deletion calls during migration.\n\n## Basic Usage\n\n```c++\n#include \"EMPointer.h\"\n#include \u003ciostream\u003e\n\nstruct Widget {\n    int id;\n    Widget(int i) : id(i) { std::cout \u003c\u003c \"Widget \" \u003c\u003c id \u003c\u003c \" created.\\n\"; }\n    ~Widget() { std::cout \u003c\u003c \"Widget \" \u003c\u003c id \u003c\u003c \" destroyed.\\n\"; }\n    void show() { std::cout \u003c\u003c \"Widget ID: \" \u003c\u003c id \u003c\u003c std::endl; }\n};\n\nint main() {\n    // Single object\n    {\n        em::pointer\u003cWidget\u003e pW1 = new Widget(1); // Allocation + RAII\n        if (pW1) {\n            pW1-\u003eshow(); // Use like a raw pointer\n\n            em::pointer\u003cWidget\u003e pW2 = pW1; // Shared ownership (ref count = 2)\n            std::cout \u003c\u003c \"Widget use count: \" \u003c\u003c pW1.use_count() \u003c\u003c std::endl;\n\n        } // pW2 goes out of scope (ref count = 1)\n          // pW1 goes out of scope (ref count = 0), Widget(1) is deleted automatically\n    }\n\n    std::cout \u003c\u003c \"-----\\n\";\n\n    // Array object\n    {\n        const size_t count = 3;\n        em::pointer\u003cWidget\u003e pWArray = em::pointer\u003cWidget\u003e(count); // MUST use size constructor\n        if (pWArray) {\n            for(size_t i = 0; i \u003c count; ++i) {\n                 pWArray[i] = Widget(10 + i); // Use operator[]\n            }\n            pWArray[1].show();\n\n            // Pointer arithmetic example (use with care)\n            em::pointer\u003cWidget\u003e pWPtr = pWArray;\n            pWPtr++; // Move to second element\n            pWPtr-\u003eshow();\n\n        } // pWPtr goes out of scope (detaches)\n          // pWArray goes out of scope, delete[] is called automatically for the array\n    }\n\n    return 0;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskillfulelectro%2Fempointer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskillfulelectro%2Fempointer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskillfulelectro%2Fempointer/lists"}