From 1c78829ab3177940adbdb7f0081b5f46c1e37763 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 27 Sep 2024 11:07:08 -0400 Subject: Introduce owning_ptr; use it for JPEG2KEncode and JPEG2KDecode. owning_ptr adapts std::unique_ptr to be a better drop-in replacement for a legacy class that formerly stored plain T* data members, and explicitly destroyed them using domain-specific destructor functions. Directly substituting std::unique_ptr into JPEG2KEncode and JPEG2KDecode was cumbersome because every such pointer declaration required a redundant template parameter describing the deleter function passed into its constructor. Moreover, it required lots of little syntax tweaks: changing every assignment to a reset() call, changing every reference to a get() call. Using owning_ptr allows us to leave the code more or less as it was before, save that assignment and destruction automatically handle the previous referenced T instance. --- indra/llcommon/owning_ptr.h | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100755 indra/llcommon/owning_ptr.h (limited to 'indra/llcommon/owning_ptr.h') diff --git a/indra/llcommon/owning_ptr.h b/indra/llcommon/owning_ptr.h new file mode 100755 index 0000000000..c0da245265 --- /dev/null +++ b/indra/llcommon/owning_ptr.h @@ -0,0 +1,71 @@ +/** + * @file owning_ptr.h + * @author Nat Goodspeed + * @date 2024-09-27 + * @brief owning_ptr is like std::unique_ptr, but easier to integrate + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Copyright (c) 2024, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_OWNING_PTR_H) +#define LL_OWNING_PTR_H + +#include +#include + +/** + * owning_ptr adapts std::unique_ptr to make it easier to adopt into + * older code using dumb pointers. + * + * Consider a class Outer with a member Thing* mThing. After the constructor, + * each time a method wants to assign to mThing, it must test for nullptr and + * destroy the previous Thing instance. During Outer's lifetime, mThing is + * passed to legacy domain-specific functions accepting plain Thing*. Finally + * the destructor must again test for nullptr and destroy the remaining Thing + * instance. + * + * Multiply that by several different Outer members of different types, + * possibly with different domain-specific destructor functions. + * + * Dropping std::unique_ptr into Outer is cumbersome for a several + * reasons. First, if Thing requires a domain-specific destructor function, + * the unique_ptr declaration of mThing must explicitly state the type of that + * function (as a function pointer, for a typical legacy function). Second, + * every Thing* assignment to mThing must be changed to mThing.reset(). Third, + * every time we call a legacy domain-specific function, we must pass + * mThing.get(). + * + * owning_ptr is designed to drop into a situation like this. The domain- + * specific destructor function, if any, is passed to its constructor; it need + * not be encoded into the pointer type. owning_ptr supports plain pointer + * assignment, internally calling std::unique_ptr::reset(). It also + * supports implicit conversion to plain T*, to pass the owned pointer to + * legacy domain-specific functions. + * + * Obviously owning_ptr must not be used in situations where ownership of + * the referenced object is passed on to another pointer: use std::unique_ptr + * for that. Similarly, it is not for shared ownership. It simplifies lifetime + * management for classes that currently store (and explicitly destroy) plain + * T* pointers. + */ +template +class owning_ptr +{ + using deleter = std::function; +public: + owning_ptr(T* p=nullptr, const deleter& d=std::default_delete()): + mPtr(p, d) + {} + void reset(T* p=nullptr) { mPtr.reset(p); } + owning_ptr& operator=(T* p) { mPtr.reset(p); return *this; } + operator T*() const { return mPtr.get(); } + T& operator*() const { return *mPtr; } + T* operator->() const { return mPtr.operator->(); } + +private: + std::unique_ptr> mPtr; +}; + +#endif /* ! defined(LL_OWNING_PTR_H) */ -- cgit v1.2.3