{"id":25117825,"url":"https://github.com/pwalig/oop_ptr","last_synced_at":"2025-04-02T12:18:57.053Z","repository":{"id":275910612,"uuid":"927359433","full_name":"pwalig/oop_ptr","owner":"pwalig","description":"smart pointer for managing objects that utilize object oriented programming paradigm of C++","archived":false,"fork":false,"pushed_at":"2025-02-05T07:48:51.000Z","size":7,"stargazers_count":0,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-05T08:32:07.467Z","etag":null,"topics":["copy-assignment","cplusplus","cpp","object-oriented-programming","oop","ownership","pointer","pointers","smart-pointer","smart-pointers"],"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/pwalig.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":"2025-02-04T20:32:49.000Z","updated_at":"2025-02-05T07:48:55.000Z","dependencies_parsed_at":"2025-02-05T08:43:42.614Z","dependency_job_id":null,"html_url":"https://github.com/pwalig/oop_ptr","commit_stats":null,"previous_names":["pwalig/oop_ptr"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwalig%2Foop_ptr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwalig%2Foop_ptr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwalig%2Foop_ptr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwalig%2Foop_ptr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pwalig","download_url":"https://codeload.github.com/pwalig/oop_ptr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246811316,"owners_count":20837753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["copy-assignment","cplusplus","cpp","object-oriented-programming","oop","ownership","pointer","pointers","smart-pointer","smart-pointers"],"created_at":"2025-02-08T03:25:46.341Z","updated_at":"2025-04-02T12:18:57.025Z","avatar_url":"https://github.com/pwalig.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# oop_ptr\n\nsmart pointer for managing objects that belong to inheritance hierarchies\n\n# Problem\n\nWhenever you wish to utilize object oriented programming paradigm of C++ you are sometimes forced to use pointers:\n\n``` c++\nclass BaseClass {\n    public:\n    int a;\n    virtual void foo() {\n        printf(\"base\\n\");\n    }\n    virtual ~BaseClass() = default;\n};\n\nclass ChildClass : public BaseClass {\n    public:\n    int b;\n    void foo() override {\n        printf(\"child\\n\");\n    }\n}\n\nint main(void) {\n    ChildClass c;\n    BaseClass b = c; // c object will get trimmed to b object\n    b.foo(); // \"base\" will be printed\n\n\n    ChildClass* cptr = new ChildClass();\n    BaseClass* bptr = cptr;\n    bptr-\u003efoo(); // \"child\" will be printed\n\n    return 0;\n}\n```\n\nProblem arises when you want to store bunch of objects that inherit from some base class in a containter like `std::vector`:\n\n``` c++\nstd::vector\u003cBaseClass*\u003e bcv;\nbcv.push_back(new ChildClass());\n\nbcv2 = bcv; // now both bcv[0] and bcv2[0] point to the same object\n// potential double free and other abnormalities can happen if you are not carefull\n```\n\nNow try putting a vector like that as a member in a class that you wish to be *Copy Assignable* or *Copy Constructable*. You will not only need to define a *destructuor* (to free dynamically allocated data), but also *Copy Assignment* *constructor* and *operator*.\n\n# Solution\n\nHere comes `oop_ptr`.\n\n`oop_ptr` makes all objects easily constuctable, copiable and destructable.\n\nOnly caveat is, that you will need to define a special function in every non-abstract object in your inheritance hierarchy. Luckily `oop_ptr.hpp` contains macros to speed up the process.\n\n``` c++\n#include \u003coop_ptr.hpp\u003e\n#include \u003ccassert\u003e\n\nclass BaseClass {\n    public:\n    int a;\n    virtual void foo() {\n        printf(\"base\\n\");\n    }\n    virtual ~BaseClass() = default;\n\n    oop_ptr_base_declare(BaseClass);\n};\n\nclass ChildClass : public BaseClass {\n    public:\n    int b;\n    void foo() override {\n        printf(\"child\\n\");\n    }\n    oop_ptr_child_declare(BaseClass);\n}\n\noop_ptr_define(BaseClass, BaseClass)\noop_ptr_define(BaseClass, ChildClass)\n\nint main(void) {\n    oop_ptr\u003cBaseClass\u003e boop = oop_ptr\u003cBaseClass\u003e(new ChildClass()); // boop will take ownership over newly allocated ChildClass instance\n    boop-\u003efoo(); // \"child\" will be printed\n\n    boop2 = boop; // boop2 will allocate it's own instance of ChildClass using ChildClass default copy constructor\n    boop2-\u003efoo(); // \"child\" will be printed\n\n    poob-\u003eb = 1;\n    poob2-\u003eb = 2;\n    assert(poob-\u003eb != boop2-\u003eb); // boop and boop2 are independent - point to different objects\n\n    // no need to delete as both boop and boop2 will automatically dealocate managed resources when exiting scope\n    return 0;\n}\n```\n\n# Usage\n\n`oop_ptr` is a header only, single include utility. Just copy [this file](https://github.com/pwalig/oop_ptr/blob/main/oop_ptr.hpp) to your project's include directory.\n\n# Features\n\n## 1. Made to be consistent with smart pointers form C++ standard library:\nwith methods like `release()` and `get()` and overloaded `-\u003e` and `*` operators\n\n## 2. Customizable:\nwith `#define`s you can include / exclude methods, operators and constructors from `oop_ptr` definition\n\n\n# Documentation\n\n``` c++\ntemplate\u003c\n    typename T\n\u003e class oop_ptr;\n```\n\n## Constructors\n\n* `oop_ptr()` - initializes managed object pointer to `nullptr`\n* `oop_ptr(T* ptr)` - takes ownership over object pointed by `ptr`\n* `oop_ptr(const T* ptr)` - copies object pointed by `ptr` into newly allocated memory, disabled by default, define `OOP_PTR_PTR_COPY_CONSTRUCTOR` to enable\n* `oop_ptr(const T\u0026 obj)` - copies `obj` into newly allocated memory\n* `oop_ptr(const oop_ptr\u003cT\u003e\u0026 other)` - copy constructor\n* `oop_ptr(oop_ptr\u003cT\u003e\u0026\u0026 other)` - move constructor\n\n## Operators\n\n* `operator= (const oop_ptr\u003cT\u003e\u0026 other)` - copy assignment operator\n* `operator= (oop_ptr\u003cT\u003e\u0026\u0026 other)` - move assignment operator\n* `operator bool` - checks if there is an associated managed object\n* `operator*`, `operator-\u003e` - dereferences pointer to the managed object\n* `operator=(const T\u0026 obj)` - destroyes currently managed object (if any) and creates a copy of supplied object, disabled by default, to enable define `OOP_PTR_OBJECT_COPY_OPERATOR`\n* `operator=(const T\u0026 obj)` - destroyes currently managed object (if any) and creates a copy of object pointed by `ptr`, disabled by default, to enable define `OOP_PTR_PTR_COPY_OPERATOR`\n* `operator=(T* ptr)` - destroyes currently managed object (if any) and takes ownership over object pointed by `ptr`, disabled by default, to enable define `OOP_PTR_PTR_MOVE_OPERATOR`\n\n## Methods\n\n* `release()` - returns a pointer to the managed object and releases the ownership\n* `get()` - returns a pointer to the managed object without releasing the ownership\n* `gettable\u003cU\u003e()` - checks if managed object is an instance of `U` (with `dynamic_cast`)\n* `release\u003cU\u003e()` - returns a pointer to the managed object, dynamic_casted to `U` and releases the ownership\n* `get\u003cU\u003e()` - returns a pointer to the managed object, dynamic_casted to `U`, without releasing the ownership\n\n## Macros\n\nIn following definitions replace `b` with name of the base class and `c` with name of the child class.\n\n* `oop_ptr_base_declare(b);` - meant to be put in base class declaration (for pure virtual method type: `oop_ptr_base_declare(b) = 0;`)\n* `oop_ptr_child_declare(b);` - meant to be put in child class declaration\n* `oop_ptr_define(b, c)` - creates method definition (for definition of base class use `oop_ptr_define(b, b)`)\n* `oop_ptr_template_base_define(b)` - meant to be put in base class declaration if the base class is a template\n* `oop_ptr_template_child_define(b, c)` - meant to be put in child class declaration if the base class is a template\n\n## Customization with `#define`s\n\n| define name | created method | defined by default |\n| --- | --- | --- |\n| `OOP_PTR_PTR_MOVE_CONSTRUCTOR` | `oop_ptr(T* ptr)` | yes |\n| `OOP_PTR_OBJECT_COPY_CONSTRUCTOR` | `oop_ptr(const T\u0026 obj)` | yes |\n| `OOP_PTR_PTR_COPY_CONSTRUCTOR` | `oop_ptr(const T* ptr)` | no |\n| `OOP_PTR_OBJECT_COPY_OPERATOR` | `operator=(const T\u0026 obj)` | no |\n| `OOP_PTR_PTR_COPY_OPERATOR` | `operator=(const T* ptr)` | no |\n| `OOP_PTR_PTR_MOVE_OPERATOR` | `operator=(T* ptr)` | no |\n\nIf you wish to customize `oop_ptr` it is encouraged that you put your `#define`s or remove existing ones directly in `oop_ptr.hpp` file.\n\n\u003e [!WARNING]  \n\u003e Do not define both: `OOP_PTR_PTR_COPY_OPERATOR` and `OOP_PTR_PTR_MOVE_OPERATOR` at once.  \n\u003e Do not define both: `OOP_PTR_PTR_COPY_CONSTRUCTOR` and `OOP_PTR_PTR_MOVE_CONSTRUCTOR` at once.\n\nIt is also possible to change name of the method generated by macros with `oop_ptr_get_copy` `#define`.\n\n``` c++\n#define oop_ptr_get_copy awesomelyNamedMethod\n```\n\nBy default (if `oop_ptr_get_copy` is not defined) macros will generate method named: `get_copy_ptr`\n\n---\n\n\u003e When in doubt look at the source code (it's not complicated).\n\n# Disclamers\n\nAlthough `oop_ptr` was created to enabe storing objects that inherit from some base class in a C++ containers or as class members, this is not a particularly cache friendly approach, since `oop_ptr` still stores a pointer, that can point anywhere, potentially creating a *cache miss*. Because of this issue i plan to create a seperate utility that would store object directly (without any extra indirection), as a separete project. I will provide a link when it's ready.\n\n# Future\n\nWith new [reflection system for C++ 26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2996r0.html) there should be a way to do all this without the need to define special functions in class definitions. I have plans for reimplementing oop_ptr using new reflection system as a separate smart pointer (`oop_ptr26`). Existing implementation will remain to be used in projects that don't want to switch to version 26 of C++.\n\nLook into [issues](https://github.com/pwalig/oop_ptr/issues) to see all planned features.\n\n# Adoption\n\nHere is a list of projects that utilize `oop_ptr`:\n* [pwalig/mesh-compiler](https://github.com/pwalig/mesh-compiler)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpwalig%2Foop_ptr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpwalig%2Foop_ptr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpwalig%2Foop_ptr/lists"}