Skip to content

Instantly share code, notes, and snippets.

@SmallJoker
Created October 7, 2024 18:37
Show Gist options
  • Save SmallJoker/2b019b27e26babb24ecac8defd9cc641 to your computer and use it in GitHub Desktop.
Save SmallJoker/2b019b27e26babb24ecac8defd9cc641 to your computer and use it in GitHub Desktop.
Re-inventing std::weak_ptr
#include <set>
#include <stdexcept> // std::runtime_error
#include <stdio.h>
#define DO_ERROR() do { throw std::runtime_error("fault"); } while(0)
class PtrAutoNullOMatic {
public:
PtrAutoNullOMatic() = default;
~PtrAutoNullOMatic()
{
for (PtrAutoNullOMatic **ptr : m_refs) {
*ptr = nullptr;
}
printf("unassign %zu\n", m_refs.size());
}
private:
void link(PtrAutoNullOMatic **ref)
{
if (*ref)
DO_ERROR();
*ref = this;
m_refs.insert(ref);
}
void unlink(PtrAutoNullOMatic **ref)
{
if (!*ref)
return;
size_t removed = m_refs.erase(ref);
if (removed == 0)
DO_ERROR();
*ref = nullptr;
}
template <typename> friend class MyWeakPtr;
std::set<PtrAutoNullOMatic **> m_refs;
};
template <typename T>
class MyWeakPtr {
static_assert(std::is_base_of<PtrAutoNullOMatic, T>::value, "T must derive from Base");
public:
~MyWeakPtr()
{
if (ref)
ref->unlink(&ref);
}
inline void assign(T *newref)
{
if (ref)
ref->unlink(&ref);
if (newref)
newref->link(&ref);
}
T *get() { return static_cast<T *>(ref); };
PtrAutoNullOMatic *ref = nullptr;
};
class Player : public PtrAutoNullOMatic {
public:
Player() { puts(__func__); }
virtual ~Player() { puts(__func__); }
int value;
};
class LuaObject {
public:
LuaObject() { puts(__func__); }
~LuaObject() { puts(__func__); }
void assign(Player *player)
{
printf("assign %p\n", player);
m_player.assign(player);
}
void check(bool expected)
{
puts(m_player.get() ? "valid" : "nullptr");
if (!!m_player.get() != expected)
DO_ERROR();
}
private:
MyWeakPtr<Player> m_player;
};
int main()
{
Player p;
{
LuaObject o;
o.assign(&p);
o.check(true);
p.~Player();
o.check(false);
}
puts("== Simple interleaved");
// call constructor manually because we destructed "p" manually
new(&p) Player();
{
LuaObject o1, o2;
o1.assign(&p);
o2.assign(&p);
o2.assign(&p);
o2.assign(nullptr);
o1.check(true);
p.~Player();
o1.check(false);
o2.check(false);
}
puts("== Assign + unassign");
new(&p) Player();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment