Коли вектори виділяються, вони використовують пам'ять на купі чи стеку?


151

Чи правдиві всі наступні твердження?

vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

Як внутрішньо розподіляється пам'ять Typeу тому vectorчи іншому контейнері STL?


Відповіді:


222
vector<Type> vect;

буде виділяти vector, тобто інформацію заголовка, на стек, але елементи у вільному сховищі ("купи").

vector<Type> *vect = new vector<Type>;

виділяє все на безкоштовний магазин.

vector<Type*> vect;

виділить vectorна стек і купу покажчиків у вільному магазині, але де ця точка визначається тим, як ви їх використовуєте (скажімо, можна вказати елемент 0 на вільний магазин і елемент 1 на стек, скажімо).


3
Але у мене є сценарій, коли я отримую помилку сегментації, коли Type підсилюється у другій декларації. Я припускав, що це тому, що тип виділявся на стек.
Фелодас

4
@Phelodas: не бачачи свого коду, це неможливо оцінити. Будь ласка, відкрийте нове запитання.
Фред Фоо

2
Про , vector<Type> vect;так як елементи на купі і інформація заголовка знаходиться в стеку, коли інформація заголовка видаляється з пам'яті, як повернення функції, що буде відбуватися з елементами пам'яті? Вони повертаються з інформацією заголовка чи ні? Якщо їх немає, це спричинить витік пам’яті?
flyrain

3
@flyrain: вектори прибирають після себе. Читайте на RAII .
Фред Фоо

1
@flyrain: це має працювати. Будь ласка, опублікуйте нове запитання з більш детальною інформацією. Якщо ви опублікуєте посилання тут, я можу переглянути його.
Фред Фоо

25
vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

Ні, vectбуде в стеці, але масив, який він використовує внутрішньо для зберігання елементів, буде знаходитися в купі. Елементи будуть знаходитися в цьому масиві.

vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

Ні. Те саме, що вище, за винятком того, що vectorклас буде також на купі.

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

vectбуде на стеці, його пункти (покажчики на Type) будуть знаходитись у купі, і ви не можете сказати, куди будуть Typeвказані вказівники. Можливо, на стеці, на купі, в глобальних даних, ніде (тобто NULLвказівники).

BTW реалізація фактично може повністю зберігати деякі вектори (як правило, невеликого розміру) на стеку. Не те, щоб я знав про будь-яку таку реалізацію, але це може.


23

Якщо припустити реалізацію, яка насправді має стек та купу (стандартний C ++ не вимагає наявності таких речей), єдиним вірним твердженням є останнє.

vector<Type> vect;
//allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

Це правда, за винятком останньої частини ( Typeне буде в стеку). Уявіть собі:

  void foo(vector<Type>& vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec.push_back(Type());
  }

  int main() {
    vector<Type> bar;
    foo(bar);
  }

Аналогічно:

 vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

Правда, крім останньої частини, з аналогічним зустрічним прикладом:

  void foo(vector<Type> *vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec->push_back(Type());
  }

  int main() {
    vector<Type> *bar = new vector<Type>;
    foo(bar);
  }

Для:

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

це правда, але тут зауважте, що Type*покажчики будуть на купі, але Typeвипадки, на які вони вказують, не повинні бути:

  int main() {
    vector<Type*> bar;
    Type foo;
    bar.push_back(&foo);
  }

у якому б контексті ти не мав би стека? Я розумію, ти кажеш, що стандарт цього не вимагає, але практично кажучи, коли ти був би без стека?
Нердтрон

3
@Nerdtron - IIRC на деяких невеликих мікроконтролерах у вас є стек викликів, який не може зберігати нічого, крім ПК (лічильник програми) в точці останнього дзвінка, готового до RET. Тому ваш компілятор може вирішити розмістити "автоматичне зберігання" (для нерекурсивних функцій) у фіксованому місці з невеликим відношенням до потоку виконання. Це може цілком розумно вирівняти всю програму. Навіть для рекурсивного випадку у вас може бути політика "стек на функцію" або окремий стек для автоматичних змінних і повертальних адрес, що робить фразу "стек" дещо безглуздою.
Flexo

Ви можете використовувати розподіл на основі купи для всього і мати "стек очищення", який управляє автоматичним зберіганням (і, можливо, deleteзанадто).
Flexo

3

Вірно лише це твердження:

vector <Type*> vect; //vect will be on stack and Type* will be on heap.

Type* покажчики розподіляються на купу, тому що кількість покажчиків може динамічно змінюватися.

vect у цьому випадку виділяється на стек, тому що ви визначили його як локальну змінну стека.


2
Тип * не вказує розподіл купи, просто вказівник на об'єкт Type. Однак це означає, що вектор зберігає вказівник на купу. int a = 5; int * ptr_to_a = & a; вектор <int *> vec; vec.push_back (ptr_to_a); (див. відповідь jpalecek)
Меттью Рассел

1

вектор має внутрішній, allocatorякий відповідає за розподіл / розміщення спогадів з heapдля vector element. Отже, як би ви не створили вектор, його elementзавжди виділяється на heap. Щодо метаданих вектора, це залежить від способу їх створення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.