Skip to content

Instantly share code, notes, and snippets.

@uliwitness
Last active April 2, 2025 22:48
Show Gist options
  • Select an option

  • Save uliwitness/931873c0b2edaa537b905418a024be04 to your computer and use it in GitHub Desktop.

Select an option

Save uliwitness/931873c0b2edaa537b905418a024be04 to your computer and use it in GitHub Desktop.
#pragma once
#include <memory>
#include <functional>
#include <exception>
/* Since shared_ptr may always be nullptr, optional<shared_ptr<T>> makes no sense, that's what it already is.
But that means we need a non-nullable version of shared_ptr. This file is it.
Prerequisites: 1. Can't be assigned a null value (like an un-checked shared_ptr)
2. Can be assigned a non-null value
3. Can be copied to a shared_ptr or another nonoptional_shared_ptr
Would probably also need nonoptional_shared_ptr-returning versions of make_shared<T> etc.
*/
template<class T>
class nonoptional_shared_ptr {
public:
nonoptional_shared_ptr(const nonoptional_shared_ptr<T>& p) : _ptr(p._ptr) {}
nonoptional_shared_ptr<T>& operator= (const nonoptional_shared_ptr<T>& p) { _ptr = p._ptr; }
operator std::shared_ptr<T> () { return _ptr; }
T* get() { return _ptr.get(); }
T* operator -> () { return _ptr.get(); }
T& operator * () { return *_ptr; }
// Add more methods here that forward shared_ptr methods so it can be used same way.
protected:
nonoptional_shared_ptr(const std::shared_ptr<T>& p) : _ptr(p) {}
std::shared_ptr<T> _ptr;
template<class B>
friend void if_nonnullptr(const std::shared_ptr<B> &possiblyNull, const std::function<void(const nonoptional_shared_ptr<B>&)> &nonnullHandler, const std::function<void(void)> &nullHandler);
template<class C, typename... _Args>
friend nonoptional_shared_ptr<C> make_nonoptional_shared(_Args&&... __args);
};
template<class T>
static void if_nonnullptr(const std::shared_ptr<T> &possiblyNull, const std::function<void(const nonoptional_shared_ptr<T>&)> &nonnullHandler, const std::function<void(void)> &nullHandler) {
if (possiblyNull) {
nonnullHandler(nonoptional_shared_ptr(possiblyNull));
} else {
nullHandler();
}
}
template<class T, typename... _Args>
static nonoptional_shared_ptr<T> make_nonoptional_shared(_Args&&... __args) {
std::shared_ptr<T> possiblyNull = std::make_shared<T>(std::forward<_Args>(__args)...);
if (!possiblyNull) {
throw std::bad_alloc();
}
return nonoptional_shared_ptr(possiblyNull);
}
#include <iostream>
#include "optional_shared_ptr.hpp"
class Bar {
public:
explicit Bar(int n) : _num(n) {}
void print() { std::cout << "Bar::_num = " << _num << std::endl; }
int _num;
};
class Foo {
public:
Foo(const nonoptional_shared_ptr<Bar>& p) : _neverNull(p) {}
void print() { _neverNull->print(); }
protected:
nonoptional_shared_ptr<Bar> _neverNull;
};
int main(int argc, const char** argv) {
std::shared_ptr<Bar> bar = std::make_shared<Bar>(42);
std::shared_ptr<Foo> dest;
if_nonnullptr<Bar>(bar,
[&dest](const nonoptional_shared_ptr<Bar>& p) {
dest = std::make_shared<Foo>(p);
},
[](){
std::cerr << "Error!" << std::endl;
});
dest->print();
nonoptional_shared_ptr<Foo> dest2 = make_nonoptional_shared<Foo>(make_nonoptional_shared<Bar>(55));
dest2->print();
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment