Nano Hash - криптовалюты, майнинг, программирование

Будут ли std::vectors внутри другого вектора перераспределяться при перераспределении первого вектора?

У меня есть вектор std::vector<std::vector<ContactPairs>> m_contactPairs;

Если я вызову m_contactPairs.push_back() или любую другую функцию, которая изменит размер самого внешнего вектора, должны ли элементы внутри этого вектора перераспределиться (внутренние элементы в этом случае будут std::vector<ContactPairs>) или внутренние векторы просто сделают неглубокую копию и продолжат указывать на такая же память у них уже есть?

Я использую Visual Studio 2010, более раннюю версию C++11, но имеющую некоторые функции в виде расширений.

27.01.2015

  • В современном С++ я ожидаю операцию перемещения вектора, которая не требует перераспределения. 27.01.2015
  • Ответ зависит от того, какую версию С++ вы используете... если вы укажете версию, то на нее будет легче ответить. 27.01.2015
  • @Mgetz - я использую Visual Studio 2010, более раннюю версию C ++ 11, но имеющую некоторые функции в виде расширений. 27.01.2015
  • @Mgetz: я не думаю, что это точно. Старые версии C++ использовали бы std::swap, чтобы избежать выделения памяти, верно? 27.01.2015
  • @MooingDuck AFAIK зависит от реализации 27.01.2015

Ответы:


1

Краткий ответ: это зависит от используемого вами стандарта и реализации библиотеки:

  • В C++98 и C++03 нет перемещения, поэтому все будет глубоко скопировано, включая перераспределение.
  • В C++11 и C++14 будет глубокая копия, включая перераспределение, или, если реализация предоставляет noexcept конструктор перемещения std::vector<ContactPairs>.
  • В грядущей версии C++17 внутренний вектор будет перемещен, а глубокое копирование выполняться не будет.

И вот рассуждение:

  1. Внутренние векторы типа std::vector<ContactPairs> имеют конструктор перемещения, который является noexcept в соответствии с будущим стандартом C++17 (начиная с N4296) и не noexcept в соответствии со стандартами C++11 и C++14, раздел [vector.modifiers]. Вы также можете найти это здесь. Однако даже реализации, совместимые с C++11 и C++14, могут указывать noexcept, поскольку реализации могут предоставлять более сильные гарантии, чем предписано стандартом (см. Стандарт C++ 17.6.5.12). Однако многие реализации этого еще не делают.

  2. Реализация std::vector<T>::push_back() необходима для обеспечения надежной безопасности исключений, т.е. е. если он бросает, нет никаких побочных эффектов. (См. стандарт C++, раздел [container.requirements.general] §10 или §11 или здесь.)

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

Реализация конструкции хода std::vector<T> с гарантией noexcept кажется тривиальной для std::vector. Я подозреваю, что комитет по стандартам, возможно, не решился включить эту гарантию в стандарт ради согласованности: для других контейнеров на основе узлов может быть полезно иметь контрольные узлы, которые требуют распределения даже для построения по умолчанию. Поскольку перемещенный из контейнера должен быть действителен после перемещения, может быть выделение, необходимое для перемещения std::list, которое, например, может привести к броску. Следовательно, нет гарантии noexcept для конструктора перемещения std::list и других стандартных типов контейнеров на основе узлов.

27.01.2015
  • ОТ: Доступную версию стандарта (которую не так-то просто найти — поиск C++ на веб-сайте ANSI не дает результатов!) см. webstore.ansi.org/ за копию за 60 долларов. Наверное, оно того стоит, если вы хотя бы изредка участвуете в подобных обсуждениях. -- Мне трудно понять, почему с меня берут деньги за результат волонтерской работы в общественных рамках. Но ценник стандартов традиционно ориентирован на корпоративного заказчика. 27.01.2015
  • Здесь есть некоторые серые зоны... В С++ 11 и С++ 14 реализации библиотеки разрешено добавлять noexcept, и соответствующая реализация может выполнять глубокую копию или перемещение в зависимости от того, помечены ли дополнительные операции в векторах noexcept . Кроме того, стратегия роста и количество внутренних копий вектора не стандартизированы, поэтому количество копий не является существенным атрибутом контейнера. Существуют реализации стандартных библиотек C++03, которые будут перемещать буферы без запуска глубоких копий (Dinkumware, BSL). 27.01.2015
  • Кстати, отсутствие требования noexcept не было связано с согласованностью, хотя большинство людей его не используют, в типе Allocator, передаваемом в контейнер, есть точка расширения. Шаблон std::vector в общем случае не может гарантировать, что распределитель может быть перемещен в место назначения без создания исключения. Распределители - это весело, большинству людей все равно, и все же они должны платить цену;) 27.01.2015
  • В С++ 11 пункт 2 частично неверен. push_back обеспечивает строгую гарантию исключения, только если содержащийся объект не генерирует исключение при копировании/перемещении. Все еще изучаю C++03. 27.01.2015
  • С++ 03 23.1.1/12 определяет push_back как эквивалент a.insert(a.end(),x) и говорит, что если исключение выдается не конструктором копирования или оператором присваивания T, никаких эффектов не будет, аналогично C++ 11, но поскольку vector не может перемещать конструкцию, которая ничего не получает, так что вы правы насчет C++03. 27.01.2015
  • @MooingDuck Ну, да, push_back() не может гарантировать никаких эффектов в случае, если тип T не обеспечивает надлежащую реализацию конструктора копирования или оператора присваивания, потому что он никак не может этого сделать. Эти операции могут касаться глобального состояния, которое имеет видимые побочные эффекты. 27.01.2015

  • 2

    В C++03 перераспределение std::vector будет копировать ("глубокое копирование") каждого элемента. Это означает, что для вашей ситуации каждый вектор будет скопирован.

    В C++11 или более поздних версиях перераспределение std::vector будет перемещать каждый элемент только в том случае, если у элементов есть конструктор перемещения noexcept.

    В Visual Studio 2010 отсутствует поддержка noexcept, поэтому вы все равно получите глубокую копию.

    27.01.2015
  • просто чтобы убедиться, означает ли копирование, что внутренние векторы должны быть перераспределены, или это поверхностная копия, когда копируется указатель на эти данные, принадлежащие внутренним векторам, и все? 27.01.2015
  • Кажется, вы не согласны с @RalphTandetzky по поводу того, объявлен ли векторный вектор движения noexcept. Когда я посмотрел в стандарте, я не смог его увидеть, хотя noexcept кажется тривиальным и описан в качестве примера в TCPPL iirc. Где эта гарантия в стандарте? 27.01.2015
  • @PeterSchneider Я сейчас изучаю это. Да, похоже, я не согласен с Ральфом Тандецки и убеждаюсь, что он прав. 27.01.2015
  • Или неисключительность внутреннего вектора движения - и, следовательно, realloc-семантика внешнего - зависит от существования движения для ContactPairs? 27.01.2015
  • @PeterSchneider просто move-ность внутреннего вектора будет означать, что ContactPairs не нужно копировать или перемещать. 27.01.2015
  • Примечание: std::vector операции перемещения не гарантированно будут noexcept (библиотеки могут добавлять спецификацию noexcept, но C++11 и C++14 этого не требуют), что означает, что он может или не может двигаться. (Я ожидаю, что библиотеки добавят спецификацию, когда они знают, что могут, что в основном зависит от распределителя) 27.01.2015
  • @DavidRodriguez-dribeas Где сказано, что библиотеки могут добавлять спецификацию noexcept? 27.01.2015
  • @RalphTandetzky: 17.6.5.12 [...] Реализация может усилить спецификацию исключения для невиртуальной функции, добавив спецификацию noexcept, не вызывающую генерацию 27.01.2015
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..