У меня могут быть полиморфные контейнеры с семантикой значения в C++?

Для SWIFT 3 вы можете использовать простую функцию

func find(objecToFind: String?) -> Int? {
   for i in 0...arrayName.count {
      if arrayName[i] == objectToFind {
         return i
      }
   }
return nil
}

. Это даст номер позиции, поэтому вы можете использовать, например,

arrayName.remove(at: (find(objecToFind))!)

Надеюсь быть полезным

32
задан Agustin Meriles 30 May 2016 в 18:49
поделиться

8 ответов

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

Одно разумное решение состоит в том, чтобы сохранить контейнерные безопасные интеллектуальные указатели. Я обычно использую повышение:: shared_ptr, который безопасно сохранить в контейнере. Обратите внимание что станд.:: auto_ptr не.

vector<shared_ptr<Parent>> vec;
vec.push_back(shared_ptr<Parent>(new Child()));

shared_ptr использует подсчет ссылок, таким образом, он не удалит базовый экземпляр, пока все ссылки не будут удалены.

24
ответ дан 27 November 2019 в 20:42
поделиться

Да, Вы можете.

библиотека повышения ptr_container предоставляет полиморфному значению семантические версии стандартных контейнеров. Только необходимо передать в указателе на выделенный "куче" объект, и контейнер возьмет владение, и все дальнейшие операции обеспечат семантику значения, за исключением исправления владения, которое приносит Вам почти всю пользу семантики значения при помощи интеллектуального указателя.

10
ответ дан 27 November 2019 в 20:42
поделиться

Я просто хотел указать на это vector< Foo> обычно более эффективно, чем vector< Foo*>. в vector< Foo> весь Foos будет смежен друг с другом в памяти. Принимая холодный TLB и кэш, первое чтение добавит страницу к TLB и вытянет блок вектора в кэши L#; последующие чтения будут использовать теплый кэш и загруженный TLB со случайными неудачными обращениями в кэш и менее частыми отказами TLB.

Контраст это с vector< Foo*>: Поскольку Вы заполняете вектор, Вы получаете * Foo из своего средства выделения памяти. Принятие Вашего средства выделения не чрезвычайно умно, (tcmalloc?) или Вы заполняете вектор медленно со временем, местоположение каждого Foo, вероятно, будет далеко друг от друга от другого Foos: возможно, только сотнями байтов, возможно, мегабайтов независимо.

В худшем случае, поскольку Вы сканируете через vector< Foo*> и разыменовывая каждый указатель Вы подвергнетесь отказу TLB и неудачному обращению в кэш - это закончит тем, что было партия медленнее, чем если бы у Вас был vector< Foo>. (Ну, в действительно худшем случае, каждый Foo был разбит на страницы к диску, и каждое чтение подвергается поиску на диске (), и читайте () для положения обратно страницы в RAM.)

Так, продолжите использовать vector< Foo> если это уместно. :-)

10
ответ дан 27 November 2019 в 20:42
поделиться

Вы могли бы также рассмотреть повышение:: любой . Я использовал его для неоднородных контейнеров. При чтении значения назад, необходимо выполнить any_cast. Это бросит bad_any_cast, если это перестанет работать. Если это происходит, можно поймать и идти дальше к следующему типу.

я верю , это бросит bad_any_cast при попытке к any_cast производного класса к его основе. Я попробовал его:

  // But you sort of can do it with boost::any.

  vector<any> valueVec;

  valueVec.push_back(any(Parent()));
  valueVec.push_back(any(Child()));        // remains a Child, wrapped in an Any.

  Parent p = any_cast<Parent>(valueVec[0]);
  Child c = any_cast<Child>(valueVec[1]);
  p.write();
  c.write();

  // Output:
  //
  // Parent: 1
  // Child: 2, 2

  // Now try casting the child as a parent.
  try {
      Parent p2 = any_cast<Parent>(valueVec[1]);
      p2.write();
  }
  catch (const boost::bad_any_cast &e)
  {
      cout << e.what() << endl;
  }

  // Output:
  // boost::bad_any_cast: failed conversion using boost::any_cast

Все, что быть сказанным, я также пошел бы shared_ptr путем сначала! Просто мысль это могло бы иметь некоторый интерес.

4
ответ дан 27 November 2019 в 20:42
поделиться

Большинство контейнерных типов хочет абстрагировать конкретную стратегию хранения, быть ею связанный список, вектор, основанный на дереве или что имеет Вас. Поэтому Вы собираетесь испытать затруднения и из-за обладания и из-за потребления вышеупомянутого пирога (т.е. пирог является ложью (NB: кто-то должен был сделать эту шутку)).

Поэтому, что сделать? Хорошо существует несколько милых опций, но большинство уменьшит до вариантов на одной из нескольких тем или комбинациях их: выбор или изобретение подходящего интеллектуального указателя, играющего с шаблонами или шаблоном, обрабатывают по шаблону некоторым умным способом, с помощью единого интерфейса для containees, который обеспечивает рычаг для реализации на - containee двойная отправка.

между Вашими двумя установленными целями существует основная сила, таким образом, необходимо решить то, что Вы хотите, затем попытайтесь разработать что-то, что получает Вас в основном, что Вы хотите. возможно сделать некоторые хорошие и неожиданные приемы, чтобы заставить указатели быть похожими на значения с достаточно умным подсчетом ссылок и достаточно умными реализациями фабрики. Основная идея состоит в том, чтобы использовать подсчет ссылок и по запросу копией и constness и (для фактора) комбинация препроцессора, шаблонов и статических правил инициализации C++ получить что-то, что максимально умно об автоматизации преобразований указателя.

я имею, в прошлом провел некоторое время, пытаясь предположить, как использовать Виртуальный Прокси / Буква Конверта / что милый прием со ссылкой считал указатели для выполнения чего-то как основание для значения семантическое программирование в C++.

И я думаю, что это могло быть сделано, но необходимо будет обеспечить справедливо закрытый, мир C#-managed-code-like в C++ (хотя один, от которого Вы могли прорваться к базовому C++ при необходимости). Таким образом, у меня есть большое сочувствие к Вашему ходу мыслей.

3
ответ дан 27 November 2019 в 20:42
поделиться

Смотрят на static_cast и reinterpret_cast
На Языке Программирования на C++, 3-м редакторе, Bjarne Stroustrup описывает его на странице 130. Существует целый раздел по этому в Главе 6.
, можно переделать Родительский класс к Дочернему классу. Это требует, чтобы Вы знали, когда каждый который. В книге доктор Stroustrup говорит о различных методах для предотвращения этой ситуации.

не делают этого. Это инвертирует полиморфизм, которого Вы пытаетесь достигнуть во-первых!

2
ответ дан 27 November 2019 в 20:42
поделиться

Только для добавления одной вещи ко всему ИНФОРМАЦИЯ 1800 года уже сказала.

Вы могли бы хотеть смотреть на "Более эффективный C++" Scott Mayers "Объект 3: Никогда не рассматривайте массивы полиморфно" для лучше понимания этой проблемы.

2
ответ дан 27 November 2019 в 20:42
поделиться

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

Это - идея, которая могла удовлетворить Вашим потребностям.

1
ответ дан 27 November 2019 в 20:42
поделиться
Другие вопросы по тегам:

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