c++ allocators

xoki87

посоветуйте литературу по аллокаторам,плз, где бы излагались общие свойства и требования без привязки к конкретным шаблонам, гуглил в нете, ничо стоящего не нашел

zya369

они должны аллоцировать и деаллоцировать

agent007new

Сам не читал, но есть небольшая глава в книжке "The C++ Standard Library - A Tutorial and Reference". http://www.cppstdlib.com/
Первое издание валяется в инете, второго - не встречал, но, вроде, работа с аллокаторами в С++11 особо не трогалась

xoki87

кстати, да, я пролистывал книжку - последнее издание, там не было про аллокаторы, просто интересно, что это такое и как ими пользоваться

agent007new

Содержание говорит обратное
19 Allocators 1023
19.1 Using Allocators as an Application Programmer .................. 1023
19.2 A User-Defined Allocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1024
19.3 Using Allocators as a Library Programmer . . . . . . . . . . . . . . . . . . . . . 1026

evgen5555

Читай сразу Майерса, где аллокаторы использовать не рекомендуется

xoki87

я начал с smart pointers в c++ std library , там был синтаксис объявления с allocator в качестве параметра, с тех пор и хотелось разобраться, что за херь, рахмет, посмотрю майерса

xoki87

сорри, ошибся, спс за исправление

agent007new

Ну если уж на то пошло, то он не не рекомендует их использовать, а рекомендует использовать аккуратно.

Совет 10. Помните о правилах и ограничениях распределителей памяти
Совет 11. Учитывайте область применения пользовательских распределителей памяти
Как показывают приведенные примеры, распределители приносят пользу во многих ситуациях. При соблюдении ограничения об эквивалентности однотипных распределителей у вас не будет проблем с применением нестандартных распределителей для управления памятью, группировки, а также использования общей памяти и других специализированных пулов.
Если учесть, что тот же shared_ptr был добавлен в стандарт сильно позже, но, все равно, использует аллокаторы, значит комитет по стандартизации, все-таки, не думает, что ими не стоит пользоваться. Хороший пример применения кастомных аллокаторов boost iterprocess, где кастомные аллокаторы выделяют шареную память для объектов. Проблема там была (не знаю, как сейчас - я сталкивался в студии 2008) - что реализация стандартной библиотеки игнорировала аллокаторы вообще, поэтому нужно было юзать реализацию контейнеров из интерпроцесса, чтобы они корректно жили в разделяемой памяти

Maurog

shared_ptr был добавлен в стандарт сильно позже, но, все равно, использует аллокаторы
в каком месте он использует аллокатор? максимум в функции make_shared. как раз есть беда в том, что ему нельзя подсунуть свой аллокатор для выделения счетчика
про VS2008 тоже интересно узнать подробности. в каком контейнере (ну не во всех же?) игнорируются аллокаторы?

agent007new

в каком месте он использует аллокатор? максимум в функции make_shared.
Есть конструкторы, которые принимает аллокатор для выделения счетчитка
template <class U, class D, class Alloc> shared_ptr (U* p, D del, Alloc alloc);
template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc);
Есть allocate_shared, которая выделяет память для объекта и счетчика (не знаю, как постандарту но в студии - одним куском
template <class T, class Alloc, class... Args>
shared_ptr<T> allocate_shared (const Alloc& alloc, Args&&... args);
как раз есть беда в том, что ему нельзя подсунуть свой аллокатор для выделения счетчика
Почему же? Там же есть rebind, которые делает все трюки с типами.
VS2010, реализацию содрал где-то с инета, добавил только туда шаблонный конструктор копирования, чтобы компилировался и вывод сделал больее информативный. Не знаю, как раскраску кода делать
 
#include <memory>
#include <string>
#include <vector>

using namespace std;

template <typename T>
class mmap_allocator: public std::allocator<T>
{
public:
typedef size_t size_type;
typedef T* pointer;
typedef const T* const_pointer;

template<typename _Tp1>
struct rebind
{
typedef mmap_allocator<_Tp1> other;
};

pointer allocate(size_type n, const void *hint=0)
{
std::cout << "Alloc " << n << " objects. " << typeid(T).name << " with size " << sizeof(T) << std::endl;
return std::allocator<T>::allocate(n, hint);
}

void deallocate(pointer p, size_type n)
{
std::cout << "Dealloc " << n << " objects. " << typeid(T).name << std::endl;
return std::allocator<T>::deallocate(p, n);
}

mmap_allocator throw: std::allocator<T> { std::cout << "Hello allocator! " << typeid(T).name << std::endl; }
mmap_allocator(const mmap_allocator &a) throw: std::allocator<T>(a) { }
template <typename T1>
mmap_allocator(const mmap_allocator<T1> &a) throw: std::allocator<T>(a) { }

~mmap_allocator throw { }
};


int main
{
//vector<int, mmap_allocator_namespace::mmap_allocator<int>> v(10);


mmap_allocator<string> alloc;
{
auto ptr = allocate_shared<string>(alloc, "324324");
}

cout << "-----------------------" << endl;

{
shared_ptr<string> ptr2(new string("3rwdfs" [](string* p){ delete p; }, alloc);
}

return 0;
}


Вывод

Hello allocator! class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
Alloc 1 objects. class std::tr1::_Ref_count_obj_alloc<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class mmap_allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > with size 48
Dealloc 1 objects. class std::tr1::_Ref_count_obj_alloc<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class mmap_allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >
-----------------------
Alloc 1 objects. class std::tr1::_Ref_count_del_alloc<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class `anonymous namespace'::<lambda0>,class mmap_allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > with size 20
Dealloc 1 objects. class std::tr1::_Ref_count_del_alloc<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class `anonymous namespace'::<lambda0>,class mmap_allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >
Press any key to continue . . .

Т.е. счетчики вполне выделяются
про VS2008 тоже интересно узнать подробности. в каком контейнере (ну не во всех же?) игнорируются аллокаторы?
Было давно, деталей щас уже не помню - что я там использовал. Проверил в 2010: вектор использует аллокатор. Вот что буст (последняя версия) по этому поводу говорит

Unfortunately, many STL implementations use raw pointers for internal data and ignore allocator pointer typedefs and others suppose at some point that the allocator::typedef is T*. This is because in practice, there wasn't need of allocators with a pointer typedef different from T* for pooled/node memory allocators.
Until STL implementations handle allocator::pointer typedefs in a generic way, Boost.Interprocess offers the following classes:

и дает свои реализации контейнеров

Maurog

Есть конструкторы, которые принимает аллокатор для выделения счетчитка
спасибо, не знал об их существовании.
Есть allocate_shared, которая выделяет память для объекта и счетчика (не знаю, как постандарту но в студии - одним куском
это аналог make_shared, просто дополнительный аргумент - аллокатор. выделяет одним куском по стандарту
20.8.2.2.6 shared_ptr creation [ util.smartptr.shared.create]
template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args);
template<class T, class A, class... Args>
shared_ptr<T> allocate_shared(const A& a, Args&&... args);
1 Requires: The expression ::new (pv) T(std::forward<Args>(args)... where pv has type void* and points to storage suitable to hold an object of type T, shall be well formed. A shall be an allocator (17.6.3.5). The copy constructor and destructor of A shall not throw exceptions.
2 Effects: Allocates memory suitable for an object of type T and constructs an object in that memory via the placement new expression ::new (pv) T(std::forward<Args>(args)...). The template allocate_shared uses a copy of a to allocate memory. If an exception is thrown, the functions have no effect.
3 Returns: A shared_ptr instance that stores and owns the address of the newly constructed object of type T.
4 Postconditions: get != 0 && use_count == 1
5 Throws: bad_alloc, or an exception thrown from A::allocate or from the constructor of T.
6 Remarks: Implementations should perform no more than one memory allocation. [ Note: This provides efficiency equivalent to an intrusive smart pointer. —end note ]
7 [ Note: These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. —end note ]
Оставить комментарий
Имя или ник:
Комментарий: