В моей программе есть несколько типов небольших объектов, которые очень часто создаются и уничтожаются в каждом потоке с помощью make_shared, и shared_ptr не будет передан другому потоку, и в этом случае я решаю написать собственный распределитель allocate_shared с повышением:: pool как его член для выделения фиксированного размера памяти в соответствии с типом.
Мой код выглядит следующим образом:
ObjectAllocator.h:
#include <boost/pool/pool.hpp>
template<typename T>
class ObjectAllocator
{
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
auto static constexpr block_size=64+sizeof(value_type);
public:
ObjectAllocator() noexcept:pool_(block_size){}
ObjectAllocator(const ObjectAllocator &other) noexcept :pool_(block_size){}
~ObjectAllocator()=default;
template<typename U>
ObjectAllocator(const ObjectAllocator<U> &other) noexcept :pool_(block_size){}
template<typename U>
ObjectAllocator& operator= (const ObjectAllocator<U> &other){
return *this;
}
ObjectAllocator<T>& operator = (const ObjectAllocator &other){
return *this;
}
template<typename U>
struct rebind{ typedef ObjectAllocator<U> other; };
T *allocate(size_type n, const void *hint=nullptr){
#ifdef _DEBUG
assert(n==1);
#endif
return static_cast<T*>(pool_.malloc());
}
void deallocate(T *ptr, size_type n){
#ifdef _DEBUG
assert(n==1);
#endif
pool_.free(ptr);
}
private:
boost::pool<> ObjectAllocator<T>::pool_(block_size);
}
template<typename T, typename U>
inline bool operator == (const ObjectAllocator<T>&, const ObjectAllocator<U>&){
return true;
}
template<typename T, typename U>
inline bool operator != (const ObjectAllocator<T>& a, const ObjectAllocator<U> &b){
return !(a==b);
}
namespace Allocator {
template <typename T>
thread_local ObjectAllocator<T> allocator;
}
main.cpp:
class ObjectA{
public:
int s=0;
void func(){
std::cout<<s<<std::endl;
}
ObjectA() {//std::cout<<"()"<<std::endl;}
~ObjectA() {//std::cout<<"~"<<std::endl;}
};
std::vector<std::shared_ptr<ObjectA>> vec;
void test(){
static uint32_t loop_count=1000*1000;
for(uint32_t i=0;i<loop_count;i++){
shared_ptr<ObjectA> packet = allocate_shared<ObjectA, ObjectAllocator<ObjectA>>(Allocator::allocator<ObjectA>);
vec.push_back(packet);
}
vec.clear();
}
std::vector<std::shared_ptr<ObjectA>> vec2;
void test2(){
static uint32_t loop_count=1000*1000;
for(uint32_t i=0;i<loop_count;i++){
shared_ptr<ObjectA> packet = allocate_shared<ObjectA, ObjectAllocator<ObjectA>>(Allocator::allocator<ObjectA>);
vec2.push_back(packet);
}
vec2.clear();
}
int main() {
std::thread thread1(test);
test2();
return 0;
}
Когда я пытаюсь проверить егоЭто терпит крах, и я понятия не имею, почему.Может ли кто-нибудь помочь сделать это правильно?Заранее спасибо.
Отладчик сообщает об ошибке сегмента в shared_ptr_base.h
void * _M_get_deleter (const std :: type_info & __ti) const noexcept {return _M_pi?_M_pi -> _ M_get_deleter (__ ti): nullptr;}
Когда я пытаюсь сделать boost :: pool статическим, он отлично работает в одном потоке и вылетает в многопоточности Отладчик сообщает об ошибке seg в shared_ptr_base.h
: _M_use_count (1), _M_weak_count (1) {}
обновление: я делаю boost :: pool статическим thread_local, и теперь он работает правильно
template<typename T>
class ObjectAllocator
{
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
auto static constexpr block_size=64+sizeof(value_type);
public:
ObjectAllocator() noexcept{}
ObjectAllocator(const ObjectAllocator &other) noexcept {}
~ObjectAllocator()=default;
template<typename U>
ObjectAllocator(const ObjectAllocator<U> &other) noexcept {}
template<typename U>
ObjectAllocator& operator= (const ObjectAllocator<U> &other){
return *this;
}
ObjectAllocator<T>& operator = (const ObjectAllocator &other){
return *this;
}
template<typename U>
struct rebind{ typedef ObjectAllocator<U> other; };
T *allocate(size_type n, const void *hint=nullptr){
#ifdef _DEBUG
assert(n==1);
#endif
return static_cast<T*>(pool_.malloc());
}
void deallocate(T *ptr, size_type n){
#ifdef _DEBUG
assert(n==1);
#endif
pool_.free(ptr);
}
private:
thread_local static boost::pool<> pool_;
};
template<typename T>
thread_local boost::pool<> ObjectAllocator<T>::pool_(block_size);
template<typename T, typename U>
inline bool operator == (const ObjectAllocator<T>&, const ObjectAllocator<U>&){
return true;
}
template<typename T, typename U>
inline bool operator != (const ObjectAllocator<T>& a, const ObjectAllocator<U> &b){
return !(a==b);
}
namespace Allocator {
template <typename T>
thread_local static ObjectAllocator<T> allocator;
}
template <typename T, typename ...Args>
inline auto custom_make_shared(Args... args){
return std::allocate_shared<T,ObjectAllocator<T>>(Allocator::allocator<T>,std::forward<Args>(args)...);
}