Как вложенные векторы выглядят в памяти?

Поэтому я подумываю о том, чтобы сделать глобальную вложенную std::vector (vector <vector <data>> V) изначально пустой, а позже в ходе программы добавлять данные в эту вложенную vector. Меня беспокоит добавление слишком большого количества элементов во время выполнения, превышение стека и его переполнение.

Итак, после некоторых исследований я понял, что внешний экземпляр vectorV — это объект в стеке, но его содержимое, такое как внутренний vector и элементы внутри внутренних vector, хранятся в куче.

Означает ли это, что мне не нужно беспокоиться о добавлении слишком большого количества элементов во вложенный вектор во время выполнения, поскольку элементы будут храниться в куче, а не в стеке?
Ниже у меня есть изображение того, как, по моему мнению, будет выглядеть вложенный вектор V в памяти. Скажите, пожалуйста, верно ли мое нынешнее понимание. Спасибо

Мой прогноз вложенной векторной памяти:

Попытка понять структуру вложенной векторной памяти и добавление слишком большого количества элементов приведет к переполнению стека.

Ваше понимание правильное — вам не нужно беспокоиться о пространстве стека при использовании std::vector, поскольку память для элементов выделяется в куче. Наличие вложенного вектора не меняет этого. В стеке может находиться только легкий «заголовок» внешнего вектора (если это, например, локальная переменная).

wohlstad 13.08.2024 18:36

... и насколько я вижу, ваш прогноз выглядит верным в тех реализациях, которые я рассмотрел.

Ted Lyngmo 13.08.2024 18:40

Дополнительное чтение:devblogs.microsoft.com/oldnewthing/20230802-00/?p=10‌​8524

許恩嘉 13.08.2024 18:54

Примечание: куча и стек — это детали реализации, а стандарт C++ описывает необходимое поведение с точки зрения динамического и автоматического хранения. Вероятно, вы никогда не увидите такого в реальной жизни, но пока соблюдаются требования, предъявляемые к динамическому и автоматическому хранению, можно использовать что угодно. Сюда входят Стоящие камни, измельченный в порошок рог единорога, пыльца пикси и начинка Заботливого медведя, пропитанная кровью ритуально убитых смурфиков. Проклятие. Внезапно стало темно.

user4581301 13.08.2024 19:06

не совсем то же самое, но в основном: stackoverflow.com/questions/55478523/…

NathanOliver 13.08.2024 19:07

Примечание: Дуг приводит очень простой пример того, как избежать вложенного вектора без необходимости изменения синтаксиса. Зачем вам это делать? Все эти различные блоки памяти действительно могут снизить производительность программы, поскольку процессору приходится преследовать все эти указатели и почти наверняка отдельно загружать данные, на которые ссылаются указатели. Обычно лучше хранить все данные в одном компактном блоке.

user4581301 13.08.2024 19:11
sizeof(V) сообщит вам, сколько байтов V занимает в стеке.
Drew Dormann 13.08.2024 19:32

Если ответ решает вашу проблему @Sliferslacker, вы можете нажать «✔», чтобы отметить его как принятый ответ. Вы также можете проголосовать за все полезные ответы (голосование и принятие выполняются отдельно). Смотрите здесь: Что мне делать, если кто-то отвечает на мой вопрос?.

wohlstad 16.08.2024 10:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
9
125
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

std::vector ни для чего не использует стек; все в векторе находится в куче.

Конечно, на всякий случай: если положить вектор в стек, как в

void foo()
{
   std::vector<...> something;
}

тогда фактическое содержимое будет находиться в куче, как я только что сказал, но будет небольшой кусочек управляющих данных, которые составляют фактический экземпляр "вектора" в стеке - например, "указатель на блок памяти, размер блока памяти, и количество используемых в настоящее время элементов».

Если вы сделаете это с вложенным вектором, как в

void foo()
{
   std::vector<std::vector<...>> something;
}

Тогда «данные управления внешним вектором» будут находиться в стеке, а все данные управления внутренним вектором, которые являются элементами содержимого внешнего вектора, будут находиться в куче.

если хочешь, попробуй что-нибудь вроде этого:

#include <vector>
#include <iostream>

int main()
{
   std::vector<int> test;
   std::cout << sizeof(test) << '\n';
   for (int i=0; i<10000; i++) test.push_back(i);
   std::cout << sizeof(test) << '\n';
}

Вы должны получить довольно небольшое число размера векторного объекта, и независимо от того, насколько сильно вы в него вдавливаете, это не изменится. И да, любой «эксперт» по C++ знает, что sizeof() объекта не может измениться, но новичку, возможно, захочется увидеть, чтобы он не менялся :-)

Спасибо, подтвердили. Верно ли это и для других контейнеров с динамическим размером, таких как очереди, стек, деки, приоритетные очереди и т. д. Где содержимое элементов находится в куче, а не в стеке?

Sliferslacker 16.08.2024 21:07

На самом деле это не предусмотрено стандартом, но на практике std::vector реализации всегда выделяют память для элементов в куче.

Следовательно, ваше понимание верно, и вам не нужно беспокоиться о переполнении стека при использовании std::vector.

Сам объект std::vector очень легкий и содержит лишь несколько элементов типа «заголовка» (один из них указывает на фактические данные в куче, другие могут указывать на размер, емкость и т. д. — это зависит от реализации).

В случае вложенного vector в стеке может находиться только «заголовок» внешнего элемента (если вы, например, используете его как локальную переменную).

Другие ответы здесь хороши и предоставляют правильную информацию. Но для наглядности вот красивая картинка:

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

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

std::vector гарантирует непрерывное расположение своих данных. Но вы видите, что он не объединяет вещи, как это делает многомерный массив. Содержащиеся объекты представляют собой векторы, которые действительно хранятся как непрерывные данные, но, как вы можете видеть, каждый векторный объект поддерживает свое собственное отдельное хранилище данных в куче.

Другие вопросы по теме

Похожие вопросы

Почему перегрузка оператора предварительного приращения не вызывается для моего пользовательского класса итератора в C++?
Синтаксический сахар для синхронизации блока кода в C++
Как ограничить функцию шаблона определенными типами?
Visual Studio C++: копирование проектов и решений с одного компьютера на другой (github не работает)
Странное поведение кнопки EnableWindow при нажатии
Можно ли с уверенностью предположить, что 32-битные числа с плавающей запятой можно напрямую сравнивать друг с другом, если значение соответствует мантиссе?
Практическое руководство: функция C++, которая настраивает тип возвращаемого значения в соответствии с потребностями вызывающей стороны
Возвращает ли low_bound() один и тот же результат с обратными итераторами вектора в порядке возрастания и прямыми итераторами вектора в порядке убывания?
Почему std::make_format_args ожидает неконстантную ссылку
C++ Существует ли быстрый многомерный массив, который позволяет использовать подмассивы разного размера?