где хранятся члены-члены класса в куче? - PullRequest
0 голосов
/ 02 октября 2011

Как класс создается в куче. Все ли члены-члены затем размещаются в куче или где-то еще. Есть ли тогда какая-то польза в распределении переменных-членов, явно указанных в куче?

struct abc {
std::vector<int> vec;
}


int main() {
abc* ptr = new abc(); //the "class" is on the heap but where is vec?
ptr->vec.push_back(42); //where will the 42 be stored?
return 0;
}

будет ли это иметь значение

struct abc {
std::vector<int>* vec_ptr;
abc() { vec_ptr = nev std::vector<int>(); }

int main() {
abc* ptr = new abc();
ptr->vec->push_back(42);
}

Ответы [ 3 ]

4 голосов
/ 02 октября 2011

Нестатические члены данных хранятся внутри объекта (экземпляра класса), частью которого они являются.

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

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

Например, скажем, вектор реализован так:

template <typename T, typename Allocator = std::allocator<T>>
class vector {
    T *data_ = nullptr;
    size_t capacity_ = 0;
    size_t used_ = 0;
    // ...
};

затем capacity_ и used_ являются частью вашего векторного объекта. Указатель data_ также является частью объекта, но память, управляемая вектором (и , указанная на на data_), не является.


Примечание по терминологии:

  • с продолжительностью автоматического хранения изначально в стеке . Как указывает Локи (а я упомянул себя в другом месте ), автоматическое локальное хранение часто реализуется с использованием стека вызовов, но это деталь реализации.
  • динамически изначально был в куче - применимо то же самое возражение.
  • Когда я говорю обычный бесплатный магазин , я имею в виду независимо от ресурса, которым управляет ::operator new. Там может быть что угодно, это еще одна деталь реализации.
0 голосов
/ 02 октября 2011

new ed объект рассматривается как непрерывное распределение. При создании нового экземпляра abc создается выделение с минимальным размером sizeof(abc).

система не выделяет членов класса отдельно при создании через new. для иллюстрации: new не вызывает new для каждого члена, подчиненного. следовательно, элементы данных хранятся в непрерывном выделении, созданном new, который является единым распределением.

в случае vector вектор внутренне использует динамическое распределение для своих элементов - это достигается с помощью отдельного выделения. это распределение выполняется в рамках реализации вектора.

поэтому члены действительно находятся в куче, но они существуют как часть экземпляра abc, и этот экземпляр использует одно распределение, исключая любые распределения, которые создают члены данных.

Есть ли тогда польза в распределении переменных-членов, явно указанных в куче?

да. Есть много причин, по которым вы можете сделать это. учитывая контекст вопроса: вы должны предпочитать объявлять своих членов ценностями, пока не будет веской причины не делать этого ( подробности здесь ). когда вам нужно объявить свой элемент как распределение кучи, всегда используйте соответствующий контейнер (например, автоматический указатель, общий указатель), потому что это сэкономит вам массу усилий, времени и сложности.

0 голосов
/ 02 октября 2011

Ваш вопрос может быть упрощен.Рассмотрим:

int main()
{
  std::vector<int> v;
  v.push_back(42);
}

«Где хранится 42

В этом примере v - это автоматическая переменная, поэтому она хранится в хранилище локальной области (обычно этостек).Но обратите внимание, что v имеет фиксированный небольшой размер - это просто объект-обработчик.Фактическая память для содержащихся элементов отдельно выделяется внутренней логикой вектора с использованием указанного распределителя (в данном случае std::allocator), который, в свою очередь, забирает всю свою память из свободного хранилища.

Все(не статичные) члены данных класса образуют часть типа данных этого класса и занимают место - это по сути то же самое, что и тупой C struct.Однако магия большинства классов библиотек C ++ заключается в том, что их члены-данные являются лишь крошечными указателями, а все данные полезной нагрузки распределяются отдельно и управляются внутренней логикой класса.с большим количеством векторных членов сам класс все еще не будет очень большим.Любой экземпляр этого класса будет выделен целиком, где угодно и как угодно (автоматически, динамически, статически), но имейте в виду, что каждый объект-член сам запросит дополнительную отдельную память для своей работы.

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