Skip to content

Commit b2d3fc1

Browse files
authored
Merge pull request #1 from cschreib/no_shared_ptr
Do not use shared_ptr for implementation, rename weak_ptr to observer_ptr
2 parents 8e465a8 + 706c646 commit b2d3fc1

File tree

5 files changed

+1364
-286
lines changed

5 files changed

+1364
-286
lines changed

README.md

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44

55
## Introduction
66

7-
This is a small header-only library, providing a unique-ownership smart pointer that can be observed with weak pointers. It is a mixture of `std::unique_ptr` and `std::shared_ptr`: it borrows the unique-ownership semantic of `std::unique_ptr` (movable, non-copiable), but allows creating `std::weak_ptr` instances to monitor the lifetime of the pointed object.
7+
This is a small header-only library, providing a unique-ownership smart pointer `observable_unique_ptr` that can be observed with non-owning pointers `observer_ptr`. It is a mixture of `std::unique_ptr` and `std::shared_ptr`: it borrows the unique-ownership semantic of `std::unique_ptr` (movable, non-copiable), but allows creating `observer_ptr` to monitor the lifetime of the pointed object (like `std::weak_ptr` for `std::shared_ptr`).
88

9-
This is useful for cases where the shared-ownership of `std::shared_ptr` is not desirable, e.g., when lifetime must be carefully controlled and not be allowed to extend, yet non-owning "weak" references to the object may exist after the object has been deleted.
9+
This is useful for cases where the shared-ownership of `std::shared_ptr` is not desirable, e.g., when lifetime must be carefully controlled and not be allowed to extend, yet non-owning/weak/observer references to the object may exist after the object has been deleted.
1010

11-
Note: Because of the unique ownership model, weak pointers locking cannot extend the lifetime of the pointed object, hence `observable_unique_ptr` provides less thread-safety compared to `std::shared_ptr`. This is also true of `std::unique_ptr`, and is a fundamental limitation of unique ownership. Do not use this library if the lifetime of your objects is not well understood.
11+
Note: Because of the unique ownership model, observer pointers cannot extend the lifetime of the pointed object, hence `observable_unique_ptr`/`observer_ptr` provides less thread-safety compared to `std::shared_ptr`/`std::weak_ptr`. This is also true of `std::unique_ptr`, and is a fundamental limitation of unique ownership. If this is an issue, you will need either to add your own explicit locking logic, or use `std::shared_ptr`/`std::weak_ptr`.
1212

1313

1414
## Usage
1515

16-
This is a header-only library. You have multiple ways to set it up:
16+
This is a header-only library requiring a C++17-compliant compiler. You have multiple ways to set it up:
1717
- just include this repository as a submodule in your own git repository and use CMake `add_subdirectory`,
1818
- use CMake `FetchContent`,
1919
- download the header and include it in your own sources.
@@ -28,35 +28,34 @@ From there, include the single header `<oup/observable_unique_ptr.hpp>`, and dir
2828
#include <cassert>
2929

3030
int main() {
31-
// Weak pointer that will outlive the object
32-
oup::weak_ptr<std::string> wptr;
31+
// Non-owning pointer that will outlive the object
32+
oup::observer_ptr<std::string> obs_ptr;
3333

3434
{
3535
// Unique pointer that owns the object
36-
auto ptr = oup::make_observable_unique<std::string>("hello");
36+
auto owner_ptr = oup::make_observable_unique<std::string>("hello");
3737

38-
// Make the weak pointer observe the object
39-
wptr = ptr;
38+
// Make the observer pointer point to the object
39+
obs_ptr = owner_ptr;
4040

41-
// Weak pointer is valid
42-
assert(!wptr.expired());
41+
// Observer pointer is valid
42+
assert(!obs_ptr.expired());
4343

44-
// It can be locked to get a (non-owning!) pointer to the object
45-
std::string* s = wptr.lock();
46-
assert(s != nullptr);
47-
std::cout << *s << std::endl;
44+
// It can be used like a regular raw pointer
45+
assert(obs_ptr != nullptr);
46+
std::cout << *obs_ptr << std::endl;
4847

4948
// The unique pointer cannot be copied
50-
auto tmp_copied = ptr; // error!
49+
auto tmp_copied = owner_ptr; // error!
5150

5251
// ... but it can be moved
53-
auto tmp_moved = std::move(ptr); // OK
52+
auto tmp_moved = std::move(owner_ptr); // OK
5453
}
5554

5655
// The unique pointer has gone out of scope, the object is deleted,
57-
// the weak pointer is now null.
58-
assert(wptr.expired());
59-
assert(wptr.lock() == nullptr);
56+
// the observer pointer is now null.
57+
assert(obs_ptr.expired());
58+
assert(obs_ptr == nullptr);
6059

6160
return 0;
6261
}
@@ -65,16 +64,12 @@ int main() {
6564

6665
## Limitations
6766

68-
The follownig limitations are imposed by the current implementation (reusing the parts from `std::shared_ptr` and `std::weak_ptr`), or features that were not implemented simply because of lack of motivation. A higher quality implementation of this API could get rid of most (if not all) of them.
67+
The follownig limitations are features that were not implemented simply because of lack of motivation.
6968

7069
- `observable_unique_ptr` does not support pointers to arrays, but `std::unique_ptr` and `std::shared_ptr` both do.
7170
- `observable_unique_ptr` does not support custom allocators, but `std::shared_ptr` does.
72-
- `observable_unique_ptr` does not have a `release()` function to let go of the ownership, which `std::unique_ptr` has.
73-
- `observable_unique_ptr` allows moving from other `observable_unique_ptr` only if the deleter type is exactly the same, while `std::unique_ptr` allows moving from a convertible deleter.
74-
- Contrary to `std::unique_ptr`, which stores the deleter in-place next to the pointer to the owned object, an `observable_unique_ptr` follows the model from `std::shared_ptr` where the deleter is type-erased and stored on the heap. Therefore, an `observable_unique_ptr` may or may not own a deleter instance; if in doubt, check `has_deleter()` before calling `get_deleter()`, or use `try_get_deleter()`.
75-
- A moved-from `observable_unique_ptr` will not own a deleter instance.
7671

7772

7873
## Notes
7974

80-
An alternative implementation of an "observable unique pointer" can be found [here](https://www.codeproject.com/articles/1011134/smart-observers-to-use-with-unique-ptr). It does not compile out of the box with gcc unfortunately, but it does contain more features (like creating an observer pointer from a raw `this`) and a lower-overhead implementation (not based on `std::shared_ptr`/`std::weak_ptr`). Have a look to check if this better suits your needs.
75+
An alternative implementation of an "observable unique pointer" can be found [here](https://www.codeproject.com/articles/1011134/smart-observers-to-use-with-unique-ptr). It does not compile out of the box with gcc unfortunately, but it does contain more features (like creating an observer pointer from a raw `this`). Have a look to check if this better suits your needs.

0 commit comments

Comments
 (0)