[对于某些情况,我正在编写一个分配器,该分配器将基本分配器作为模板类型,除了将allocate()
和deallocate()
调用转发给基础分配器成员外,什么也不做。使用此自定义分配器创建std::vector
可以正常工作。 我尝试编写一个make_shared
包装器,默认情况下将使用dummy_allocator<T, std::allocator<T>>
,但未成功。
#include <memory> namespace test { template<typename T, typename base_allocator=std::allocator<T>> class dummy_allocator { public: typedef typename std::allocator_traits<base_allocator>::size_type size_type; typedef typename std::allocator_traits<base_allocator>::difference_type difference_type; typedef typename std::allocator_traits<base_allocator>::pointer pointer; typedef typename std::allocator_traits<base_allocator>::const_pointer const_pointer; typedef typename std::allocator_traits<base_allocator>::value_type value_type; template<class U> struct rebind { typedef dummy_allocator<U, typename std::allocator_traits<base_allocator>::template rebind_alloc<U>> other; }; template<typename... Args> dummy_allocator(Args &&... args) noexcept : alloc(std::forward<Args>(args)...) {} dummy_allocator(const dummy_allocator& a) = default; [[nodiscard]] T *allocate(std::size_t n) { T *p = alloc.allocate(n); return p; } void deallocate(T *p, std::size_t size) noexcept { alloc.deallocate(p, size); } private: base_allocator alloc; }; /// Allocate using a wrapped version of passed in allocator template <typename T, typename Alloc, typename... Args> std::shared_ptr<T> allocate_shared(const Alloc& alloc, Args&&... args) { auto dummy_alloc = dummy_allocator<T, Alloc>(alloc); return std::allocate_shared<T>(dummy_alloc, std::forward<Args>(args)...); } /// Create a shared pointer from a default stl allocator wrapped in profile allocator. template <typename T, typename... Args> std::shared_ptr<T> make_shared(Args&&... args) { return test::allocate_shared<T>(std::allocator<T>(), std::forward<Args>(args)...); } } // namespace test int main() { auto ptr = test::make_shared<double>(); return 0; }
当我运行上面的代码时,编译器生成了一些奇怪的模板替换失败错误:
/usr/include/c++/10.1.0/bits/shared_ptr_base.h:679:43: required from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = double; _Alloc = test::dummy_allocator<double, std::allocator<double> >; _Args = {}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ /usr/include/c++/10.1.0/bits/shared_ptr_base.h:1371:71: required from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = test::dummy_allocator<double, std::allocator<double> >; _Args = {}; _Tp = double; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’ /usr/include/c++/10.1.0/bits/shared_ptr.h:408:59: required from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = test::dummy_allocator<double, std::allocator<double> >; _Args = {}; _Tp = double]’ /usr/include/c++/10.1.0/bits/shared_ptr.h:859:14: required from ‘std::shared_ptr<_Tp> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = double; _Alloc = test::dummy_allocator<double, std::allocator<double> >; _Args = {}]’ /home/ray/home/testing/src/alloc.cpp:44:35: required from ‘std::shared_ptr<_Tp> test::allocate_shared(const Alloc&, Args&& ...) [with T = double; Alloc = std::allocator<double>; Args = {}]’ /home/ray/home/testing/src/alloc.cpp:50:36: required from ‘std::shared_ptr<_Tp> test::make_shared(Args&& ...) [with T = double; Args = {}]’ /home/ray/home/testing/src/alloc.cpp:86:46: required from here /home/ray/home/testing/src/alloc.cpp:25:82: error: no matching function for call to ‘std::allocator<std::_Sp_counted_ptr_inplace<double, test::dummy_allocator<double, std::allocator<double> >, __gnu_cxx::_S_atomic> >::allocator(const test::dummy_allocator<double, std::allocator<double> >&)’ 25 | dummy_allocator(Args &&... args) noexcept : alloc(std::forward<Args>(args)...) {} | ^ In file included from /usr/include/c++/10.1.0/list:61, from /home/ray/home/testing/src/alloc.cpp:3: /usr/include/c++/10.1.0/bits/allocator.h:157:2: note: candidate: ‘template<class _Tp1> constexpr std::allocator< <template-parameter-1-1> >::allocator(const std::allocator<_Tp1>&) [with _Tp1 = _Tp1; _Tp = std::_Sp_counted_ptr_inplace<double, test::dummy_allocator<double, std::allocator<double> >, __gnu_cxx::_S_atomic>]’ 157 | allocator(const allocator<_Tp1>&) _GLIBCXX_NOTHROW { } | ^~~~~~~~~ /usr/include/c++/10.1.0/bits/allocator.h:157:2: note: template argument deduction/substitution failed: /home/ray/home/testing/src/alloc.cpp:25:82: note: ‘const test::dummy_allocator<double, std::allocator<double> >’ is not derived from ‘const std::allocator<_Up>’ 25 | dummy_allocator(Args &&... args) noexcept : alloc(std::forward<Args>(args)...) {} | ^ In file included from /usr/include/c++/10.1.0/list:61, from /home/ray/home/testing/src/alloc.cpp:3: /usr/include/c++/10.1.0/bits/allocator.h:147:7: note: candidate: ‘constexpr std::allocator< <template-parameter-1-1> >::allocator(const std::allocator< <template-parameter-1-1> >&) [with _Tp = std::_Sp_counted_ptr_inplace<double, test::dummy_allocator<double, std::allocator<double> >, __gnu_cxx::_S_atomic>]’ 147 | allocator(const allocator& __a) _GLIBCXX_NOTHROW | ^~~~~~~~~ /usr/include/c++/10.1.0/bits/allocator.h:147:34: note: no known conversion for argument 1 from ‘const test::dummy_allocator<double, std::allocator<double> >’ to ‘const std::allocator<std::_Sp_counted_ptr_inplace<double, test::dummy_allocator<double, std::allocator<double> >, __gnu_cxx::_S_atomic> >&’ 147 | allocator(const allocator& __a) _GLIBCXX_NOTHROW | ~~~~~~~~~~~~~~~~~^~~ /usr/include/c++/10.1.0/bits/allocator.h:144:7: note: candidate: ‘constexpr std::allocator< <template-parameter-1-1> >::allocator() [with _Tp = std::_Sp_counted_ptr_inplace<double, test::dummy_allocator<double, std::allocator<double> >, __gnu_cxx::_S_atomic>]’ 144 | allocator() _GLIBCXX_NOTHROW { } | ^~~~~~~~~ /usr/include/c++/10.1.0/bits/allocator.h:144:7: note: candidate expects 0 arguments, 1 provided ... (The above error basically is repeated 2 more times)
尤其是此错误似乎代表了所发生的问题:
error: no matching function for call to ‘std::allocator<std::_Sp_counted_ptr_inplace<double, test::dummy_allocator<double, std::allocator<double> >, __gnu_cxx::_S_atomic> >::allocator(const test::dummy_allocator<double, std::allocator<double> >&)’
基本上说“在
dummy_allocator
的构造函数中,您不能将dummy_allocator
传递给std::allocator
的构造函数”。但是我没有那样做。在allocate_shared
中,我将std::allocator
传递到dummy_allocator
。
我真的很伤脑筋,看不懂编译器错误,但对我做错的事情没有任何结论。任何帮助将不胜感激!
编辑:我想我有一种预感,无论魔术shared_ptr在做什么,它都在尝试做我的dummy_allocator的副本构造函数,而完美的转发是捕获副本构造而不是实际的副本构造函数。 但是,我有no
想法,因为它是可变参数模板,因此无法解决此问题,并且我不能在完美的转发构造函数中使用std::is_same<Args, dummy_allocator>
作为require子句。因此,正如Daniel Langr所指出的那样,仅复制构造dummy_allocator将会失败。我通过以下require子句解决了该问题:
... template <typename T1, typename ...TV> struct is_dummy : std::is_same<typename std::decay<T1>::type, dummy_allocator<T, base_allocator>>{ }; template<typename... Args> requires (!is_dummy<Args...>::value) dummy_allocator(Args &&... args) noexcept : alloc(std::forward<Args>(args)...) {} dummy_allocator() = default; dummy_allocator(const dummy_allocator& a) = default; ...
但是,这还不足以解决
shared_ptr
问题,因为错误会更长一些... *
[在某些情况下,我正在编写一个分配器,该分配器将基本分配器作为模板类型,除了将allocate()和deallocate()调用转发给基础分配器成员之外,什么也不做。 ...
只需删除可变参数的构造函数并添加这两个: