Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Аллокатор памяти и STL


Автор: SIRIUStar 23.1.2009, 00:13
Всем привет! У меня задачка появилась: Необходимо подменить стандартный аллокатор памяти allocator<type> на свой в STL. Я кое что накопал по этому поводу, но это не работает, во всяком случае правильно. Возникает ошибка в менеджере памяти, Но этого быть никак не может! Он проверенный и хорошо работает. Поэтому я думаю что не правильно наследовал, хотя все вроде делают так.. Можно было бы перегрузить new, но для меня это не выход, хотя с перегруженным new работает нормально) smile 

Код

#include <iostream>

#include <algorithm>
#include <cmath>
#include <string>

#include <vector>
#include <list>
#include <map>

#include "winnie_alloc.h"

using namespace std;

template<class usertype> class CNovaAlloc : public std::allocator<usertype>
{
public:

    template<class _Other> struct rebind
    {
        typedef CNovaAlloc<_Other> other;
    };

    template<class _Other> CNovaAlloc(const CNovaAlloc<_Other> & p) throw() { }

    template<class _Other> CNovaAlloc<usertype> & operator=(const CNovaAlloc<_Other> & p)
   {
        return (*this);
    }
    
    CNovaAlloc(const CNovaAlloc<usertype> & p) throw() {}

    CNovaAlloc() throw() {}

    ~CNovaAlloc() throw() {}

    allocator<usertype>::pointer allocate(allocator<usertype>::size_type n)
    { 
        void * p = Winnie::Alloc(n);
        return reinterpret_cast<pointer>(p);
    }

    void deallocate(allocator<usertype>::pointer p, allocator<usertype>::size_type n)
    { 
        Winnie::Free(p);
    }
};



Если кто знает как правильно наследовать аллокатор.. ну или какието другие решения, буду признателен.

Автор: Lycifer 23.1.2009, 15:07
SIRIUStar - не когда не наследуйся от STL(разумеется кроме exception)
Алакатор свой вставляешь через шаблон(смотри сигнатуру используемого класса)

Автор: georain 23.1.2009, 18:46
SIRIUStar, что за ошибка?

Если Winnie::Alloc(n)  и Winnie::Free(n) заменить на обычные alloc и free работает?

Lycifer, почему нельзя от stl наследоваться?

Автор: Alek86 23.1.2009, 18:56
Цитата(georain @  23.1.2009,  18:46 Найти цитируемый пост)
почему нельзя от stl наследоваться?

ибо у них не предусмотрено виртуальных деструкторов
правда слово "никогда" тут некстати, ибо иногда это делать можно


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

Автор: georain 23.1.2009, 19:22
Вот пример аллокатора, можно просто заменить Allocate и Free;

Код


// выделяет память
void* Allocate(size_t size);
// освобождает память
void Free(void * ptr, size_t size) throw();


// stl-совместимый аллокатор
template <typename T>
class Allocator{
public:

    typedef size_t        size_type;
    typedef ptrdiff_t    difference_type;
    typedef T*            pointer;
    typedef const T*    const_pointer;
    typedef T&            reference;
    typedef const T&    const_reference;
    typedef T            value_type;

    Allocator(){}
    Allocator(const Allocator&){}
    template <typename U>
    Allocator(const Allocator<U>&){}
    ~Allocator(){}

    template <typename U>
    struct rebind {
        typedef Allocator<U> other;
    };

    pointer address (reference value) const {
        return &value;
    }

    const_pointer address (const_reference value) const {
        return &value;
    }

    size_type max_size() const{
        return std::numeric_limits<size_t>::max() / sizeof(T);
    }

    pointer allocate(size_type num, const_pointer hint = 0){
        return static_cast<pointer>(Allocate(num*sizeof(T)));
    }

    void construct(pointer p, const_reference value){
        new((void*)p) T(value);
    }

    void destroy(pointer p){
        p->~T();
    }

    void deallocate(pointer p, size_type num){
        Free((void*)p, num*sizeof(T));
    }

}; // class Allocator

template<>
class Allocator<void>{
    public:

    typedef void*        pointer;
    typedef const void*    const_pointer;
    typedef void        value_type;

    template <class U>
    struct rebind{
        typedef Allocator<U> other;
    };
};


    template <class T1, class T2> inline
    bool operator== (const Allocator<T1>&, const Allocator<T2>){
        return true;
    }
    template <class T1, class T2> inline
    bool operator!= (const Allocator<T1>&, const Allocator<T2>){
        return false;
    }

Автор: SIRIUStar 24.1.2009, 23:11
SIRIUStar - не когда не наследуйся от STL(разумеется кроме exception)
Алакатор свой вставляешь через шаблон(смотри сигнатуру используемого класса)


Хм, чего не знал того не знал)) тоесть получется, что память забирается, но не освобождается при таком наследовании?

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

это я понимаю.. но думал что от std::allocator наследоваться будет правильней)

Спасибо за примеры)) Да и кстате при замене аллокатора винни на связку malloc/free возникает ошибка Corruption Heap  smile (страшновато звучит) будем пробовать дальше)

Автор: georain 25.1.2009, 01:59
SIRIUStar, попробуй использовать мой пример сначала с malloc/free, потом с винни, напиши что будет

Автор: Lazin 25.1.2009, 02:13
SIRIUStar, просто убери из кода
Код

 : public std::allocator<usertype>

Автор: SIRIUStar 26.1.2009, 17:10
Всем спасибо) вопрос закрыт,  нашел у себя ошибку)
Дело в том, что метод allocate нужно реализовывать так:

Код

allocator<usertype>::pointer allocate(allocator<usertype>::size_type n)

        void *p = Winnie::Alloc(n * sizeof(usertype));

        return reinterpret_cast<pointer>(p);
}
// А у меня был просто
void *p = Winnie::Alloc(n);



Этот момент я упустил, без примеров бы долго тупил))  smile  smile 

Автор: BasMan 14.3.2009, 20:17
Думаю создавать отдельную тему не стоит, поэтому задам вопрос тут smile

Существует приложение + плагины выполненные в виде dll/so библиотек, в приложении существует хост-объект, при инициализации библиотек им передается указатель на хост-объект (библы скомпилены с хидером в котором описаны все интерфейсы хоста и других предоставляемых приложением объектов, после получения указателя на хост, плагин от хоста получает указатель на фабрику объектов clsExecutorInterface, а затем регистрирует все доступные в плагине реализации clsExecutor, в дальнейнем, экземпляры зарегеных классов создаются в любом порядке. Строковые параметры в данный момент передаются как char*. Собственно это была преамбула, а теперь вопрос: если я заменю все char*на string (соответственно переписав необходимый и зависимый код), какой аллокатор памяти будет использоваться в экземплярах классов созданных на фабрике? Я думаю, что аллокатор из приложения, а не из библиотек, но все таки, кто может подсказать?

Автор: Lazin 14.3.2009, 20:25
из библиотек, шаблоны инстанциируются во время компиляции
К.О.

Автор: mes 14.3.2009, 20:25
не советовал бы использовать std::string (да и другие стл-типы)  для передачи параметров между библиотекой и приложением.

Автор: BasMan 14.3.2009, 20:31
Вот поэтому и решил посоветоваться, т.к. вроде бы и библиотека, но объект создается на фабрике основного приложения, и все параметры передаются/принимаются уже этим объектом. Спасибо за информацию.

Автор: sparn 15.3.2009, 02:16
Если память выделяется в приложении используется аллокатор приложения, если выделяется в библиотеке используется аллокатор библиотеки и они могут быть абсолютно разными, потому что модули могут быть скомпилированны различными компиляторами с различными настройками или использовать третьесторонние аллокаторы (Heap мэнеджер ОС Windows или такие как tcmalloc, horde и др.). Я думаю понятно что произойдёт если попытаться освободить память одним аллокатором выделенную на самом деле другим аллокатором. Отсюда следует золотое правило: освобождать память там где выделил. 
Если уж придётся передавать данные так что они должны будут освободиться в другом модуле то можно чтоб например приложение или библиотека предоставляла соответствующее API для выделения и освобождения памяти (это довольно общепринятая практика в больших библиотеках/модульных системах). Но динамическая подмена аллокаторов(чтоб использовать например в СТЛе аллокатор предоставляемый приложением) это отдельный изврат да и вообще редко когда осуществимо.

Автор: BasMan 15.3.2009, 06:40
Именно поэтому использовал с самого начала char*, просто точно не знал где выделяется память если объект создается на фабрике основного приложения (как я понял из постов выше, даже если объект создается на фабрике хоста, то память все равно выделяется в длл/со)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)