Как передать пользовательский распределитель в std::basic_ostringstream в C++11?

Я хочу использовать настраиваемый распределитель для выделения памяти из свободного списка для std::basic_ostringstream. Вот мой пользовательский распределитель, который я хочу использовать:

template <class Tp>

    struct NAlloc {
        typedef Tp value_type;
        typedef value_type* pointer;
        typedef const value_type* const_pointer;
        typedef value_type& reference;
        typedef const value_type& const_reference;
        typedef std::size_t size_type;
        typedef std::ptrdiff_t difference_type;

        NAlloc() = default;
        template <class T> NAlloc(const NAlloc<T>&) {}
        Tp* allocate(std::size_t n) {
            n *= sizeof(Tp);
            memoryPool *memPool = memoryPool::GetInstance(10);//get memory pool instance
            std::cout << "allocating " << n << " bytes\n";
            return static_cast<Tp*>(memPool->allocate(n)); //get memory from pool
        }
        void deallocate(Tp* p, std::size_t n) {
            std::cout << "deallocating " << n*sizeof*p << " bytes\n";
            memoryPool *memPool = memoryPool::GetInstance(10);
            memPool->deallocate(static_cast<void*>(p));//return memory to pool
        }

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

Затем я использую его следующим образом:

typedef std::basic_string<char, std::char_traits<char>, NAlloc<char>> OstringStream;

****Проблема:****

int main()
{
    OstringStream os; //Object creation
    os << " Hello, this is OstreamStream class with memory pool";  //here I am getting error
}

Ошибка: «OstringStream {также известный как std::basic_string‹char, std::char_traits‹char>, NAlloc‹char> >}» не является производным от «std::basic_ostream‹_CharT, _Traits>»


person user3059007    schedule 23.01.2018    source источник
comment
Что у тебя с этим не так?   -  person Toby Speight    schedule 23.01.2018
comment
Если я сделаю это, OstringStream os, os ‹‹ Hello ; std::cout ‹‹os.str() .... Я получаю сообщение об ошибке. OstringStream не использует функциональность std::basic_ostringstream. Ошибка: «OstringStream {также известный как std::basic_string‹char, std::char_traits‹char›, NAlloc‹char› ›}» не является производным от «std::basic_ostream‹_CharT, _Traits›»   -  person user3059007    schedule 23.01.2018
comment
Вам нужно отредактировать вопрос, чтобы показать свою проблему (а не добавлять комментарий). Напишите минимально воспроизводимый пример и включите его в текст вопроса. Спасибо.   -  person Toby Speight    schedule 23.01.2018
comment
Вам нужно на самом деле задать вопрос, если вы хотите помощи. Пожалуйста, укажите это в вопросе, а не в комментарии.   -  person Justin Randall    schedule 23.01.2018
comment
Вам не нужно перегружать оператор ‹‹, чтобы использовать его на вашем объекте?   -  person atru    schedule 23.01.2018
comment
Я так не думаю. Я просто хочу использовать свой собственный распределитель для распределения и освобождения памяти. Функция-член std::basic_ostringstream должна работать (без перегрузки). Я подозреваю, что класс распределения для std::basic_ostringstream работает некорректно.   -  person user3059007    schedule 23.01.2018


Ответы (1)


Ваш тип OstringStream является определением типа std::basic_string, а не std::basic_ostream. Вот почему вы получаете ошибку от operator<<. Левый операнд должен быть объектом, производным от std::basic_ostream, как и говорится в сообщении об ошибке.

Сам std::basic_ostream вообще не использует распределитель. Он использует std::basic_streambuf для всех операций ввода-вывода. Например, std::ostringstream использует std::stringbuf, который использует значение по умолчанию std::allocator.

В C++11 std::basic_ostringstream имеет необязательный параметр шаблона Allocator, который он передает своему внутреннему std::basic_stringbuf. Таким образом, вместо этого вы можете написать свой typedef следующим образом:

typedef std::basic_ostringstream<char, std::char_traits<char>, NAlloc<char>> OstringStream;

int main()
{
    OstringStream os;
    os << " Hello, this is OstringStream with memory pool";
}

В более ранних версиях C++ вам пришлось бы:

  1. определите typedef std::basic_stringbuf, который использует ваш пользовательский распределитель вместо распределителя по умолчанию.

  2. создайте стандартный объект std::ostream, который использует экземпляр вашего пользовательского типа stringbuf.

Например:

typedef std::basic_stringbuf<char, std::char_traits<char>, NAlloc<char> > Stringbuf_NAlloc;

class OstringStream : public Stringbuf_NAlloc, public std::ostream
{
public:
    OstringStream() : Stringbuf_NAlloc(std::ios_base::out), std::ostream(this) {}
};

int main()
{
    OstringStream os;
    os << " Hello, this is OstringStream with memory pool";
}

В любом случае знайте, что метод os.str() больше не будет возвращать стандартный std::string, который использует распределитель по умолчанию. Он вернет std::basic_string, который вместо этого использует ваш пользовательский распределитель. Это вызовет проблемы при попытке присвоить возвращаемое значение os.str() стандартному std::string, например:

std::string s = os.str(); // error!

ошибка: преобразование из 'std::__cxx11::basic_ostringstream‹char, std::char_traits‹char>, NAlloc>::__string_type {он же std::__cxx11::basic_string‹char, std::char_traits‹char>, NAlloc> }' в нескалярный тип 'std::__cxx11::string {он же std::__cxx11::basic_string‹char>}' запрошен

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

person Remy Lebeau    schedule 24.01.2018
comment
большое спасибо!. Мне очень нравится ваша поясняющая часть. Я также планирую использовать пользовательский распределитель для basic_string. - person user3059007; 24.01.2018
comment
Это отлично работает для распределителей без сохранения состояния. ctor ostring_stream() не принимает объект распределителя, но ctor stringbuf делает это. Так что ваш пример для старого С++ выглядит многообещающе. - person brian beuning; 14.02.2019