Подход RAII для контейнера контейнеров?

#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 бы то, что у него нет проблемы с изменяемыми ссылками.