From 071ab82a7a10904b52f4a0253402b6978c5d1c81 Mon Sep 17 00:00:00 2001
From: Ichthyostega
Date: Sat, 31 May 2025 01:40:36 +0200
Subject: [PATCH] clean-up: review and validate `ScopedPtrVect`
This is a plausible concept, and without obvious replacement
(letting aside `boost::ptr_vector`). It has a small number
of usages, and provides a dedicated API to show the
semantics when used as implementation of an ''Object Manager''
The original implementation used private inheritance from `std::vector`,
which is not really justified here, since we neither use the ''template method''
pattern, nor want to gain access to protected internals.
So this can be replaced with a private member.
---
src/lib/scoped-collection.hpp | 2 +-
src/lib/scoped-ptrvect.hpp | 116 +++++++++++++-------------
tests/library/scoped-ptrvect-test.cpp | 2 +-
wiki/thinkPad.ichthyo.mm | 106 +++++++++++++++++++----
4 files changed, 150 insertions(+), 76 deletions(-)
diff --git a/src/lib/scoped-collection.hpp b/src/lib/scoped-collection.hpp
index 1fb95e857..3ccad4b0f 100644
--- a/src/lib/scoped-collection.hpp
+++ b/src/lib/scoped-collection.hpp
@@ -50,7 +50,7 @@
** is sufficient to hold any of these subclass instances. This condition
** is protected by a static assertion (compilation failure).
** @warning when using subclasses, a virtual dtor is mandatory
- ** @warning deliberately \em not threadsafe
+ ** @warning deliberately **not threadsafe**
**
** @see ScopedCollection_test
** @see scoped-ptrvect.hpp quite similar, but using individual heap pointers
diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp
index a485965c7..c00456b31 100644
--- a/src/lib/scoped-ptrvect.hpp
+++ b/src/lib/scoped-ptrvect.hpp
@@ -1,5 +1,5 @@
/*
- SCOPED-PTRVECT.hpp - simple noncopyable lifecycle managing collection of pointers
+ SCOPED-PTRVECT.hpp - simple noncopyable lifecycle managing collection of pointers
Copyright (C)
2009, Hermann Vosseler
@@ -13,20 +13,24 @@
/** @file scoped-ptrvect.hpp
** Managing lifecycle for a collection of objects. Sometimes we need to
- ** build and own a number of objects, including lifecycle management.
+ ** build and own a number of objects, including lifecycle management.
** For example, a service provider may need to maintain a number of individual
** process handles. The solution here is deliberately kept simple, it is
** similar to using a STL container with shared_ptr(s), but behaves rather
- ** like std::unique_ptr. It provides the same basic functionality as
- ** boost::ptr_vector, but doesn't require us to depend on boost-serialisation.
+ ** like std::unique_ptr.
**
** Some details to note:
** - contained objects accessed by reference, never NULL.
** - the exposed iterator automatically dereferences
- ** - TODO: detaching of objects...
- ** - TODO: retro-fit with RefArray interface
**
- ** @warning deliberately \em not threadsafe
+ ** @warning deliberately **not threadsafe**
+ ** @remark This library class provides the same basic functionality as
+ ** `boost::ptr_vector`, but doesn't require us to depend on boost-serialisation.
+ ** Furthermore, Boost provides several variants of containers and a much more
+ ** feature-rich API, also with the ability to clone / move containers;
+ ** yet we prefer to leave out most functionality, in favour of adding
+ ** a dedicated API with #manage() and #detach() to indicated semantics.
+ ** And we value the ability to integrate with Lumiera Forward Iterators.
**
** @see scoped-ptrvect-test.cpp
** @see scoped-holder.hpp
@@ -55,23 +59,23 @@ namespace lib {
/**
* Simple vector based collection of pointers,
* managing lifecycle of the pointed-to objects.
- * Implemented as a non-copyable object, based on a
- * vector of bare pointers (private inheritance)
+ * Implemented as a non-copyable object, based
+ * on a vector of bare pointers.
*/
template
class ScopedPtrVect
- : std::vector,
- util::NonCopyable
+ : util::NonCopyable
{
- typedef std::vector _Vec;
- typedef typename _Vec::iterator VIter;
+ using _Vec = std::vector;
+ using VIter = typename _Vec::iterator;
- typedef RangeIter RIter;
- typedef PtrDerefIter IterType;
+ using RIter = RangeIter;
+ using IterType = PtrDerefIter;
- typedef typename IterType::ConstIterType ConstIterType;
- typedef typename IterType::WrappedConstIterType RcIter;
+ using ConstIterType = typename IterType::ConstIterType;
+ using RcIter = typename IterType::WrappedConstIterType;
+ _Vec vec_;
public:
typedef size_t size_type;
@@ -81,20 +85,20 @@ namespace lib {
- ScopedPtrVect ()
- : _Vec()
+ ~ScopedPtrVect()
+ {
+ clear();
+ }
+
+ ScopedPtrVect()
+ : vec_{}
{ }
explicit
ScopedPtrVect (size_type capacity)
- : _Vec()
+ : vec_{}
{
- _Vec::reserve (capacity);
- }
-
- ~ScopedPtrVect ()
- {
- clear();
+ vec_.reserve (capacity);
}
@@ -107,9 +111,9 @@ namespace lib {
manage (T* obj)
{
REQUIRE (obj);
- try
+ try
{
- this->push_back (obj);
+ vec_.push_back (obj);
return *obj;
}
catch(...)
@@ -128,35 +132,33 @@ namespace lib {
* Otherwise, NULL will be returned and the
* collection of managed objects remains unaltered
* @note EX_STRONG
- * @todo TICKET #856 better return a Maybe instead of a pointer?
*/
T*
detach (void* objAddress)
{
T* extracted = static_cast (objAddress);
- VIter pos = std::find (_Vec::begin(),_Vec::end(), extracted);
- if (pos != _Vec::end() && bool(*pos))
+ VIter pos = std::find (vec_.begin(),vec_.end(), extracted);
+ if (pos != vec_.end() and *pos != nullptr)
{
extracted = *pos;
- _Vec::erase(pos); // EX_STRONG
+ vec_.erase(pos); // EX_STRONG
return extracted;
}
- return NULL;
+ return nullptr;
}
void
clear()
- {
- VIter e = _Vec::end();
- for (VIter i = _Vec::begin(); i!=e; ++i)
- if (*i)
+ {
+ for (T*& p : vec_)
+ if (p)
try {
- delete *i;
- *i = 0;
+ delete p;
+ p = nullptr;
}
ERROR_LOG_AND_IGNORE (library, "Clean-up of ScopedPtrVect");
- _Vec::clear();
+ vec_.clear();
}
@@ -165,26 +167,26 @@ namespace lib {
T&
operator[] (size_type i)
{
- return *get(i);
+ return * get(i);
}
- typedef IterType iterator;
- typedef ConstIterType const_iterator;
+ using iterator = IterType;
+ using const_iterator = ConstIterType;
- iterator begin() { return iterator (allPtrs()); }
- iterator end() { return iterator ( RIter() ); }
- const_iterator begin() const { return const_iterator::build_by_cast (allPtrs()); }
- const_iterator end() const { return const_iterator::nil(); }
+ iterator begin() { return iterator (allPtrs()); }
+ iterator end() { return iterator ( RIter() ); }
+ const_iterator begin() const { return const_iterator::build_by_cast (allPtrs()); }
+ const_iterator end() const { return const_iterator::nil(); }
/* ====== proxied vector functions ==================== */
- size_type size () const { return _Vec::size(); }
- size_type max_size () const { return _Vec::max_size(); }
- size_type capacity () const { return _Vec::capacity(); }
- bool empty () const { return _Vec::empty(); }
+ size_type size() const { return vec_.size(); }
+ size_type max_size() const { return vec_.max_size(); }
+ size_type capacity() const { return vec_.capacity(); }
+ bool empty() const { return vec_.empty(); }
private:
@@ -192,7 +194,7 @@ namespace lib {
T*
get (size_type i)
{
- T* p (_Vec::at (i));
+ T* p (vec_.at (i));
if (!p)
throw lumiera::error::Invalid("no valid object at this index");
else
@@ -201,15 +203,15 @@ namespace lib {
/** @internal access sequence of all managed pointers */
RIter
- allPtrs ()
+ allPtrs()
{
- return RIter (_Vec::begin(), _Vec::end());
+ return RIter{vec_.begin(), vec_.end()};
}
RIter
- allPtrs () const
+ allPtrs() const
{
- _Vec& elements = util::unConst(*this);
- return RIter (elements.begin(), elements.end());
+ _Vec& elements = util::unConst(this)->vec_;
+ return RIter{elements.begin(), elements.end()};
}
};
diff --git a/tests/library/scoped-ptrvect-test.cpp b/tests/library/scoped-ptrvect-test.cpp
index 0e054c2f1..c8bfb6307 100644
--- a/tests/library/scoped-ptrvect-test.cpp
+++ b/tests/library/scoped-ptrvect-test.cpp
@@ -125,7 +125,7 @@ namespace test{
// Verify correct behaviour of iteration end
- CHECK (! (holder.end()));
+ CHECK (not holder.end());
CHECK (isnil (holder.end()));
VERIFY_ERROR (ITER_EXHAUST, *holder.end() );
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 59a7acfa9..e45fc2ba5 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -163462,11 +163462,15 @@ Since then others have made contributions, see the log for the history.
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -163494,7 +163498,8 @@ Since then others have made contributions, see the log for the history.
-
+
+
@@ -163516,22 +163521,26 @@ Since then others have made contributions, see the log for the history.
-
+
+
+
+
-
+
+
-
+
-
+
@@ -163549,7 +163558,7 @@ Since then others have made contributions, see the log for the history.
-
+
@@ -163592,7 +163601,7 @@ Since then others have made contributions, see the log for the history.
-
+
@@ -163607,6 +163616,8 @@ Since then others have made contributions, see the log for the history.
+
+
@@ -163618,8 +163629,9 @@ Since then others have made contributions, see the log for the history.
-
-
+
+
+
@@ -163630,15 +163642,75 @@ Since then others have made contributions, see the log for the history.
...hat bereits keinerlei Verwendungen mehr (hab es wohl schrittweise durch std::ref() ersetzt ... ohne eigens darauf zu achten)
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...was man auch daran sieht, daß es das gleiche Konezpt in Boost gibt; wäre da nicht Boost-serialisation, dann könnte man das als Ersatz nehmen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ außerdem habe ich hier bereits pervasiv mit einem Typ-Präfix _Vect:: dekoriert
+
+
+
+
+
+
+
+
+
+
+ ...was darauf hindeutet, daß ich bereits Probleme mit der Eindeutigkeit von Namen hatte, bzw. die Notation ohnehin verwirrend war.
+
+
+
+
+
+
+