Skip to content

Instantly share code, notes, and snippets.

@mightbxg
Last active April 16, 2022 04:04
Show Gist options
  • Save mightbxg/e52d67c2cdcea11ec9ac512b72986090 to your computer and use it in GitHub Desktop.
Save mightbxg/e52d67c2cdcea11ec9ac512b72986090 to your computer and use it in GitHub Desktop.
Object pool in c++
///@brief Object pool that manages objects with std::shared_ptr.
///@note The object will be reused only when it's released outside the pool.
template <typename T>
class SharedPtrObjectPool {
protected:
struct CalleeHelper {
};
public:
using Ptr = std::shared_ptr<T>;
SharedPtrObjectPool()
: iter_(objects_.end())
{
}
///@brief Release all objects managed by this pool.
void reset()
{
objects_.clear();
iter_ = objects_.end();
}
///@brief Get num of objects in this pool.
[[nodiscard]] size_t capacity() const
{
return objects_.size();
}
///@brief Retrieve one object with given initializing arguments.
/// The arguments will be passed to constructor if a new object is created.
/// And if an old object is reused, \p reset function will be called with these args.
///@param reset The member function of T that takes the same arguments as the constructor.
///@param args The arguments passed to constructor or \p reset.
///@return The retrieved object (shared_ptr).
template <typename Functor = CalleeHelper, typename... Args>
Ptr get(Functor reset = {}, Args&&... args)
{
if (objects_.empty()) {
return objects_.emplace_back(std::make_shared<T>(std::forward<Args>(args)...));
}
if (iter_ == objects_.end()) {
// list end reached, move iterator to the beginning.
iter_ = objects_.begin();
}
// look for a vacant object
for (size_t i = 0; i < objects_.size(); ++i) {
if (iter_->use_count() == 1) {
// call reset function with given parameters
if constexpr (!std::is_same_v<Functor, CalleeHelper>) {
static_assert(std::is_invocable<Functor, T&, Args...>::value, "Reset function not invocable with given args!");
std::invoke(reset, **iter_, std::forward<Args>(args)...);
}
break;
}
if (++iter_ == objects_.end()) {
iter_ = objects_.begin();
}
}
if (iter_->use_count() > 1) {
// no vacant object found, construct a new one.
iter_ = objects_.emplace(std::next(iter_), std::make_shared<T>(std::forward<Args>(args)...));
}
return *(iter_++);
}
protected:
std::list<Ptr> objects_;
typename std::list<Ptr>::iterator iter_;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment