#c #c 11 #vector
#c #c 11 #вектор
Вопрос:
Предполагая, что my T
является вектором typedef std::vector<ofSomething> T;
(обычно это вектор размером около 4-5 МБ, его дорого воссоздавать и сохранять в том виде, в каком он есть в структуре данных)
итак, учитывая :
- указатели
- ссылки
- интеллектуальные указатели
Я должен создать контейнер векторов, или я должен каким-то образом соединить все эти векторы, мне интересно, какой наилучший подход в соответствии с философией RAII.
std::container<T*>
или
std::container<Tamp;>
или
std::container<unique_ptr<T>>
с указателями мне нужно явно вызывать деструктор, и это на самом деле совсем не похоже на RAII.
со ссылками это в основном то же самое, что и с указателями.
с помощью интеллектуальных указателей я получаю то, что хочу, если удаляю или просто «отбрасываю» объект, представляющий интеллектуальный указатель.
Является ли набор интеллектуальных указателей действительно хорошей идеей для контейнера контейнеров? Я не знаю, они здесь для выражения права собственности, а не для автоматического управления памятью, похоже, я делаю что-то не так с неправильной философией, в то же время у меня есть несколько больших контейнеров для обработки, пока они не «истекут» или они больше не нужны.
Что вы предлагаете?
Комментарии:
1.
std::container<T>
. Тот факт, чтоT
может содержать несколько мегабайт, не имеет значения, если он никогда не копируется (читайте о семантике перемещения)2.
std::container<Tamp;>
невозможно как есть.3. Я публикую здесь, так как это слишком болтливо, чтобы быть ответом: RAII работает в любом случае, если вы делаете это правильно . Указатели? Не забудьте правильно распределять и освобождать в конструкторах / деструкторах. Интеллектуальные указатели? Они заботятся об очистке памяти вне области видимости. У вас не может быть std::vector ссылок 🙂
4. мой пример должен был быть как можно более общим, не зацикливайтесь на невозможности
Tamp;
внутри стандартных контейнеров.5. @milleniumbug По какой-то причине, когда я впервые ответил, у меня в голове было, что речь идет о контейнерах
std::array
. Возможно, потому, что тогда смысл вопроса имеет смысл.
Ответ №1:
Если вам нужен вектор векторов, и вы хотите RAII, то ответ настолько прост:
std::vector<std::vector<T>> v;
… никаких ссылок или указателей не видно.
Если вас беспокоит перемещение внутренних контейнеров по мере роста внешнего вектора, сгладьте его:
std::vector<T>
и оберните индексацию, чтобы i = x*W y
.
Комментарии:
1. с помощью этого попробуйте удалить вектор по
x
индексу и посмотреть, сколько изменений вам нужно выполнить в памяти. Это хорошо, но это также показывает, что вектор — это 1 фрагмент памяти, и он не настолько гибкий, когда вам нужно несколько объектов, которые, вероятно, будут иметь разное время жизни.2. @user2485710: тогда зарезервируйте то, что вам нужно заранее. Реализовать семантику перемещения. Сгладить структуру. Нет необходимости усложнять это.
3. @user2485710 Вы не указали свои требования. Похоже, вы используете антипаттерн for-if .
4. @milleniumbug Я ленив, семантика перемещения сделает это за меня, я просто пытался оптимизировать вещи, это также проблема с удобочитаемостью кода, если вы собираетесь вводить новый шаблон, вы будете делать код немного менее понятным каждый раз, когда вы это делаете. Переместить семантику это стандартно, и оно исходит из самого языка.
5. @user2485710 в зависимости от реализации передача содержимого в вектор не обязательно копирует-конструирует все содержащие объекты, даже если требуется перераспределение памяти. Вы также можете использовать std::deque или std::list вместо этого, чтобы гарантировать это.
Ответ №2:
Как вы говорите, с необработанным указателем вам нужно будет самостоятельно управлять памятью — поцарапайте это. Вы не можете хранить ссылку в стандартном контейнере, потому что распределители не определены для ссылочных типов, и вам все равно нужно как-то распределять свои объекты в куче — вычеркните это. Он std::unique_ptr
будет выполнять управление памятью для вас и фактически компилировать — это выигрывает … от вашего выбора.
Но как насчет std::container<T>
? Это также будет работать нормально и не будет иметь никаких проблем с ручным управлением памятью. Он также выиграет от семантики перемещения, поэтому вам не нужно беспокоиться о копируемых векторах. Вы также избегаете дополнительного уровня косвенности.
Очевидно, что использование a std::unique_ptr
ограничивает то, что вы можете делать с вашим контейнером. Если вам нужно иметь возможность копировать его и / или его элементы, вы захотите std::shared_ptr
вместо этого.
Комментарии:
1. что касается ссылок, я просто предполагал «любой вид контейнера», мой пример был действительно общим. Если я не ошибаюсь, я тут и там слышал несколько ссылок на то, что интеллектуальные указатели не являются оптимальным выбором для автоматического управления памятью, я также помню этот раздел выступления Шона Парента на канале 9 о том, насколько хороши интеллектуальные указатели, и они, вероятно, не так хороши для памяти. В любом случае я вижу вашу точку зрения, которая на самом деле является моей первоначальной точкой зрения.
2. @user2485710 Я не видел этого разговора, но это звучит не совсем правильно. Интеллектуальные указатели не так хороши для памяти?
3. В этом выступлении Шон Парент в конечном итоге определяет интеллектуальные указатели «так же хорошо, как глобальные переменные», что звучит для меня не очень круто, особенно для управления памятью, но в его выступлении не было слишком много технических деталей, возможно, некоторые тонкие ссылки на философию интеллектуальных указателей и их собственные политики, но чтоИз этого разговора я понял, что умные указатели не так хороши для этого, но я не совсем понял его точку зрения и почему.
4. @user2485710 Шон Парент специально говорил о
shared_ptr
том, что он «так же хорош, как глобальная переменная», потому что, как и глобальная переменная, вы не можете быть уверены, где указатель используется в другом месте программы.5. @user2485710 Я только что посмотрел его выступление, и да, он на самом деле говорит в более общем плане об изменяемой ссылочной семантике (явно не говоря об этом). Что касается RAII, умные указатели великолепны. Но да, лучшим выбором интеллектуального указателя здесь было
unique_ptr
бы то, что у него нет проблемы с изменяемыми ссылками.