https://github.com/pwalig/oop_ptr
smart pointer for managing objects that utilize object oriented programming paradigm of C++
https://github.com/pwalig/oop_ptr
copy-assignment cplusplus cpp object-oriented-programming oop ownership pointer pointers smart-pointer smart-pointers
Last synced: 2 months ago
JSON representation
smart pointer for managing objects that utilize object oriented programming paradigm of C++
- Host: GitHub
- URL: https://github.com/pwalig/oop_ptr
- Owner: pwalig
- License: mit
- Created: 2025-02-04T20:32:49.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2025-02-05T07:48:51.000Z (4 months ago)
- Last Synced: 2025-02-05T08:32:07.467Z (4 months ago)
- Topics: copy-assignment, cplusplus, cpp, object-oriented-programming, oop, ownership, pointer, pointers, smart-pointer, smart-pointers
- Language: C++
- Homepage:
- Size: 6.84 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# oop_ptr
smart pointer for managing objects that belong to inheritance hierarchies
# Problem
Whenever you wish to utilize object oriented programming paradigm of C++ you are sometimes forced to use pointers:
``` c++
class BaseClass {
public:
int a;
virtual void foo() {
printf("base\n");
}
virtual ~BaseClass() = default;
};class ChildClass : public BaseClass {
public:
int b;
void foo() override {
printf("child\n");
}
}int main(void) {
ChildClass c;
BaseClass b = c; // c object will get trimmed to b object
b.foo(); // "base" will be printedChildClass* cptr = new ChildClass();
BaseClass* bptr = cptr;
bptr->foo(); // "child" will be printedreturn 0;
}
```Problem arises when you want to store bunch of objects that inherit from some base class in a containter like `std::vector`:
``` c++
std::vector bcv;
bcv.push_back(new ChildClass());bcv2 = bcv; // now both bcv[0] and bcv2[0] point to the same object
// potential double free and other abnormalities can happen if you are not carefull
```Now 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*.
# Solution
Here comes `oop_ptr`.
`oop_ptr` makes all objects easily constuctable, copiable and destructable.
Only 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.
``` c++
#include
#includeclass BaseClass {
public:
int a;
virtual void foo() {
printf("base\n");
}
virtual ~BaseClass() = default;oop_ptr_base_declare(BaseClass);
};class ChildClass : public BaseClass {
public:
int b;
void foo() override {
printf("child\n");
}
oop_ptr_child_declare(BaseClass);
}oop_ptr_define(BaseClass, BaseClass)
oop_ptr_define(BaseClass, ChildClass)int main(void) {
oop_ptr boop = oop_ptr(new ChildClass()); // boop will take ownership over newly allocated ChildClass instance
boop->foo(); // "child" will be printedboop2 = boop; // boop2 will allocate it's own instance of ChildClass using ChildClass default copy constructor
boop2->foo(); // "child" will be printedpoob->b = 1;
poob2->b = 2;
assert(poob->b != boop2->b); // boop and boop2 are independent - point to different objects// no need to delete as both boop and boop2 will automatically dealocate managed resources when exiting scope
return 0;
}
```# Usage
`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.
# Features
## 1. Made to be consistent with smart pointers form C++ standard library:
with methods like `release()` and `get()` and overloaded `->` and `*` operators## 2. Customizable:
with `#define`s you can include / exclude methods, operators and constructors from `oop_ptr` definition# Documentation
``` c++
template<
typename T
> class oop_ptr;
```## Constructors
* `oop_ptr()` - initializes managed object pointer to `nullptr`
* `oop_ptr(T* ptr)` - takes ownership over object pointed by `ptr`
* `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
* `oop_ptr(const T& obj)` - copies `obj` into newly allocated memory
* `oop_ptr(const oop_ptr& other)` - copy constructor
* `oop_ptr(oop_ptr&& other)` - move constructor## Operators
* `operator= (const oop_ptr& other)` - copy assignment operator
* `operator= (oop_ptr&& other)` - move assignment operator
* `operator bool` - checks if there is an associated managed object
* `operator*`, `operator->` - dereferences pointer to the managed object
* `operator=(const T& 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`
* `operator=(const T& 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`
* `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`## Methods
* `release()` - returns a pointer to the managed object and releases the ownership
* `get()` - returns a pointer to the managed object without releasing the ownership
* `gettable()` - checks if managed object is an instance of `U` (with `dynamic_cast`)
* `release()` - returns a pointer to the managed object, dynamic_casted to `U` and releases the ownership
* `get()` - returns a pointer to the managed object, dynamic_casted to `U`, without releasing the ownership## Macros
In following definitions replace `b` with name of the base class and `c` with name of the child class.
* `oop_ptr_base_declare(b);` - meant to be put in base class declaration (for pure virtual method type: `oop_ptr_base_declare(b) = 0;`)
* `oop_ptr_child_declare(b);` - meant to be put in child class declaration
* `oop_ptr_define(b, c)` - creates method definition (for definition of base class use `oop_ptr_define(b, b)`)
* `oop_ptr_template_base_define(b)` - meant to be put in base class declaration if the base class is a template
* `oop_ptr_template_child_define(b, c)` - meant to be put in child class declaration if the base class is a template## Customization with `#define`s
| define name | created method | defined by default |
| --- | --- | --- |
| `OOP_PTR_PTR_MOVE_CONSTRUCTOR` | `oop_ptr(T* ptr)` | yes |
| `OOP_PTR_OBJECT_COPY_CONSTRUCTOR` | `oop_ptr(const T& obj)` | yes |
| `OOP_PTR_PTR_COPY_CONSTRUCTOR` | `oop_ptr(const T* ptr)` | no |
| `OOP_PTR_OBJECT_COPY_OPERATOR` | `operator=(const T& obj)` | no |
| `OOP_PTR_PTR_COPY_OPERATOR` | `operator=(const T* ptr)` | no |
| `OOP_PTR_PTR_MOVE_OPERATOR` | `operator=(T* ptr)` | no |If 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.
> [!WARNING]
> Do not define both: `OOP_PTR_PTR_COPY_OPERATOR` and `OOP_PTR_PTR_MOVE_OPERATOR` at once.
> Do not define both: `OOP_PTR_PTR_COPY_CONSTRUCTOR` and `OOP_PTR_PTR_MOVE_CONSTRUCTOR` at once.It is also possible to change name of the method generated by macros with `oop_ptr_get_copy` `#define`.
``` c++
#define oop_ptr_get_copy awesomelyNamedMethod
```By default (if `oop_ptr_get_copy` is not defined) macros will generate method named: `get_copy_ptr`
---
> When in doubt look at the source code (it's not complicated).
# Disclamers
Although `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.
# Future
With 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++.
Look into [issues](https://github.com/pwalig/oop_ptr/issues) to see all planned features.
# Adoption
Here is a list of projects that utilize `oop_ptr`:
* [pwalig/mesh-compiler](https://github.com/pwalig/mesh-compiler)