политика выделения std :: string - PullRequest
3 голосов
/ 11 января 2012

Я немного запутался с некоторыми базовыми реализациями строк. Я изучал источник, чтобы понять внутреннюю работу и узнать что-то новое. Я не могу полностью понять, как память управляется.

Просто некоторые лакомые кусочки из базовой реализации строки

  • Необработанный распределитель для типа char

    typedef typename _Alloc::template rebind<char>::other _Raw_bytes_alloc;
    
  • ... тогда при выделении Rep помещается в выделенный буфер __size рассчитывается так же, чтобы соответствовать символам

    size_type __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep);
    void* __place = _Raw_bytes_alloc(__alloc).allocate(__size);
    _Rep *__p = new (__place) _Rep;
    
  • Это то, как символьные данные выбираются из буфера _Rep

    _CharT* _M_refdata() throw()
    {
        return reinterpret_cast<_CharT*>(this + 1);
    }
    
  • Настройка персонажа - для одного типа пути

    _M_assign(__p->_M_refdata(), __n, __c);
    

Что меня беспокоит, так это то, что необработанный распределитель имеет тип char, но выделенная память может содержать объект _Rep плюс символьные данные (которые не обязательно должны быть типом char)

Кроме того, почему (или, скорее, как) вызов _M_refdata знает, где находится начало (или конец) символьных данных в буфере (то есть this+1)

Редактировать: this+1 просто перемещает внутренний указатель на следующую позицию после объекта _Rep?

У меня есть базовые представления о выравнивании и преобразовании памяти, но, похоже, это выходит за рамки всего, что я прочитал.

Кто-нибудь может помочь или указать мне более информативный материал для чтения?

Ответы [ 2 ]

5 голосов
/ 11 января 2012

Вам не хватает места размещения нового.Строка

_Rep *__p = new (__place) _Rep;

инициализирует новый _Rep -объект в __place.Пространство для этого уже было выделено ранее (то есть, размещение нового не выделяется само по себе, это фактически только вызов конструктора).

Арифметика указателей в C и C ++ говорит вам, что this + 1указатель, который указывает sizeof(*this) байт справа от this.Поскольку ранее было выделено (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep) байт, пробел после объекта _Rep используется для символьных данных.Таким образом, макет выглядит так:

| _Rep |  (__capacity + 1) * _CharT  |
0 голосов
/ 11 января 2012

Распределители, такие как C malloc, возвращают указатели на байты, а не объекты.Таким образом, тип возвращаемого значения - char * или void *.

. Где-то в стандартах C и C ++ есть пункт, который явно разрешает переинтерпретировать приведение между char и любым другим типом объекта.Это связано с тем, что C часто требуется обрабатывать объекты как байтовые массивы (как при записи на диск или сетевой сокет), а также нужно обрабатывать байтовые массивы как объекты (например, при выделении диапазона памяти или чтении с диска).

Для защиты от проблем с псевдонимами и оптимизацией вам не разрешено приводить один и тот же char * к различным типам объектов, и после того, как вы навели char * на тип объекта, выне разрешается изменять значение объекта путем записи в байты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...