如何设置从 C++ 中的 RAII 样式智能对象池获取的对象?

How to set object that is acquired from RAII style smart object pool in C++?

我使用 RAII 风格的智能对象池,我想将获取的对象设置为另一个 class 的成员。

T.C 建议的智能对象池。 :

template <class T, class D = std::default_delete<T>>
class SmartObjectPool 
{
    private:
        struct ReturnToPool_Deleter {
            explicit ReturnToPool_Deleter(std::weak_ptr<SmartObjectPool<T, D>* > pool) : pool_(pool) {

            }

            void operator()(T* ptr) {
                if (auto pool_ptr = pool_.lock())
                    (*pool_ptr.get())->add(std::unique_ptr<T, D>{ptr});
                else
                    D{}(ptr);
            }
            private:
                std::weak_ptr<SmartObjectPool<T, D>* > pool_;
        };

    public:
        using ptr_type = std::unique_ptr<T, ReturnToPool_Deleter >;

        SmartObjectPool() : this_ptr_(new SmartObjectPool<T, D>*(this)) {}
        virtual ~SmartObjectPool(){}

        void add(std::unique_ptr<T, D> t) {
            pool_.push(std::move(t));
        }

        ptr_type acquire() {
            if (pool_.empty())
                throw std::out_of_range("Cannot acquire object from an empty pool.");

            ptr_type tmp(pool_.top().release(),
                            ReturnToPool_Deleter{
                            std::weak_ptr<SmartObjectPool<T, D>*>{this_ptr_}});
            pool_.pop();
            return std::move(tmp);
        }

        bool empty() const {
            return pool_.empty();
        }

        size_t size() const {
            return pool_.size();
        }

    private:
        std::shared_ptr<SmartObjectPool<T, D>* > this_ptr_;
        std::stack<std::unique_ptr<T, D> > pool_;
};

和Setterclass我想将获取的对象设置为另一个class(Setter)的成员:

class Setter {
    public:
        void setValue(SmartObjectPool<int>::ptr_type value) {
            m_value = std::move(value);
        }
    private:
        SmartObjectPool<int>::ptr_type m_value;
};

和主要实现:

int main()
{

SmartObjectPool<int> pool;
pool.add(std::make_unique<int>());
assert(pool.size() == 1u);
{
  auto obj = pool.acquire();
  Setter setter;
  setter.setValue(std::move(obj));
  assert(pool.size() == 0u);
}
assert(pool.size() == 1u);
auto obj = pool.acquire();

return 0;

}

而且我得到一个关于 ReturnToPool_Deleter 构造函数的编译错误:

In file included from /usr/include/c++/5/functional:55:0,
                 from /usr/include/c++/5/memory:79,
                 from src/main.cpp:1:
/usr/include/c++/5/tuple: In instantiation of ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base() [with long unsigned int _Idx = 1ul; _Head = SmartObjectPool<int>::ReturnToPool_Deleter]’:
/usr/include/c++/5/tuple:353:15:   required from ‘constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl() [with long unsigned int _Idx = 1ul; _Head = SmartObjectPool<int>::ReturnToPool_Deleter]’
/usr/include/c++/5/tuple:202:29:   required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl() [with long unsigned int _Idx = 0ul; _Head = int*; _Tail = {SmartObjectPool<int>::ReturnToPool_Deleter}]’
/usr/include/c++/5/tuple:602:20:   required from ‘constexpr std::tuple<_T1, _T2>::tuple() [with _T1 = int*; _T2 = SmartObjectPool<int>::ReturnToPool_Deleter]’
/usr/include/c++/5/bits/unique_ptr.h:158:14:   required from ‘constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr() [with _Tp = int; _Dp = SmartObjectPool<int>::ReturnToPool_Deleter]’
src/main.cpp:59:7:   required from here
/usr/include/c++/5/tuple:105:22: error: no matching function for call to ‘SmartObjectPool<int>::ReturnToPool_Deleter::ReturnToPool_Deleter()’
       : _M_head_impl() { }
                      ^
src/main.cpp:11:22: note: candidate: SmartObjectPool<T, D>::ReturnToPool_Deleter::ReturnToPool_Deleter(std::weak_ptr<SmartObjectPool<T, D>*>) [with T = int; D = std::default_delete<int>]
             explicit ReturnToPool_Deleter(std::weak_ptr<SmartObjectPool<T, D>* > pool)
                      ^
src/main.cpp:11:22: note:   candidate expects 1 argument, 0 provided
src/main.cpp:10:16: note: candidate: SmartObjectPool<int>::ReturnToPool_Deleter::ReturnToPool_Deleter(const SmartObjectPool<int>::ReturnToPool_Deleter&)
         struct ReturnToPool_Deleter {
                ^
src/main.cpp:10:16: note:   candidate expects 1 argument, 0 provided
src/main.cpp:10:16: note: candidate: SmartObjectPool<int>::ReturnToPool_Deleter::ReturnToPool_Deleter(SmartObjectPool<int>::ReturnToPool_Deleter&&)
src/main.cpp:10:16: note:   candidate expects 1 argument, 0 provided
src/main.cpp: In function ‘int main()’:
src/main.cpp:87:10: note: synthesized method ‘constexpr Setter::Setter()’ first required here
   Setter setter;
          ^
Makefile:17: recipe for target 'obj/main.o' failed
make: *** [obj/main.o] Error 1

问题:如何将获取的对象设置为另一个class的成员?

问题出在下面一行

Setter setter;

此行尝试默认构造一个 Setter,但 Setter 不可默认构造。 Setter 的默认构造函数被隐式删除,因为它有一个 SmartObjectPool<int>::ptr_type 成员,它本身不是默认构造的。

SmartObjectPool<int>::ptr_typestd::unique_ptr<T, ReturnToPool_Deleter > 的别名。现在让我们看看 cppreferencestd::unique_ptr<T, Deleter>.

的默认构造函数有什么看法

1) Constructs a std::unique_ptr that owns nothing. Value-initializes the stored pointer and the stored deleter. Requires that Deleter is DefaultConstructible and that construction does not throw an exception.

如您所见,如果 Deleter 是可默认构造的,则只能默认构造一个 unique_ptr,但在您的情况下,这是不正确的:ReturnToPool_Deleter 不是默认可构造。

你可以做这样的事情,而不是做你现在正在做的事情:

using Deleter = std::function<void(T* ptr)>;
using ptr_type = std::unique_ptr<T, Deleter>;

然后

auto deleter = [pool_ = std::weak_ptr<SmartObjectPool<T, D>*>{this_ptr_} ](T* ptr) {
    if (auto pool_ptr = pool_.lock()) {
        (*pool_ptr.get())->add(std::unique_ptr<T, D>{ptr});
    } else {
        D{}(ptr);
    }
};

ptr_type tmp(pool_.top().release(), deleter);