LINUX.ORG.RU

[c++] какие контейнеры использовать?

 


0

0

Нужно:

— Постоянные адреса уже существующих элементов контейнера (чтобы оно не менялось при изменении контейнера).
— Быстрый доступ в (не знаю каком, см. ниже про OpenMP) порядке.
— Хорошая скорость копирования.

Абсолютно пофиг на скорость добавления и удаления элементов.
Размер заранее известен (не во время компиляции, а непосредственно перед созданием).

Что тут лучше использовать и почему?

Конечная цель — создать контейнер, заполнить его 10000 объектами. Далее в цикле (I) миллион раз запустить цикл (II), в котором запускается член-функция (рассчёты) для каждого из объектов. Причём цикл II запускать многопоточно (с использованием OpenMP). Каждые 1000 шагов цикла I делать в памяти копию контейнера.

Такие дела. Что выбрать? Совсем не обязательно STL-ное.
А что выбрать, если то же самое, но требуется динамическое добавление-удаление элементов (пофиг, с какой скоростью... причём добавлять элементы надо только в конец)

★★★★★

Последнее исправление: Obey-Kun (всего исправлений: 4)

И насчёт копирования, я вообще не уверен, нужно ли это.

Дело в том, что массив считается долго и каждые 1000 шагов его копия должна передаваться на визуализатор. Не уверен, как тут поступить, особенно если визуализатор и модель запущены в разных потоках. Но скорее всего таки свою копию передавать.

Obey-Kun ★★★★★
() автор топика

массив, без заморочек

yoghurt ★★★★★
()
Ответ на: комментарий от Legioner

тупо new?

блин, под утро после мутатени с Qt такие простые вещи почему-то не приходят в голову.

так и сделаю, если никто ниже по топику не отговорит.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

ну а соответственно, если создавать класс, то действительно new:

class MySet {
  MyClass m_my_class_arr;
  unsigned int m_my_class_arr_num_elements;
  MySet(int i) :
    m_my_class_arr(new MyClass [i]),
    m_my_class_arr_num_elements(i)
  {  }
  // ...........
};

Как-то так.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Т.к нужно чтобы адреса элементов не менялись при вставке/удалении то нужно список. Чтобы он быстро копировался нужно размещать его в массиве(списке массивов, ок). Вобщем все просто. Список объектов и список свободных элементов в массиве.

anonymous
()
Ответ на: комментарий от anonymous

+1 при требовании неизменности адресов элементов вариантов немного, вернее один - список.

SilentBob
()
Ответ на: комментарий от Obey-Kun

> а если то же самое, но размер динамический?

std::vector. После создания и заполнения столь же эффективен как «голый» массив, плюс можно менять размер. Если размер заранее известен - можно сразу создать нужного размера. Копируется тоже быстро.

new[] в данном случае использовать не советую - велик шанс где-нибудь забыть delete [] и получить утечку памяти.

slav ★★
()

Используй std::vector< boost::shared_ptr<MyClass> > - и адреса объектов меняться не будут, и доступ по индексу быстрый. А всякие голые массивы оставь для смелых и храбрых, у которых памяти или времени на отладку много ;)

archimag ★★★
()
Ответ на: комментарий от archimag

> std::vector< boost::shared_ptr<MyClass> > - и адреса объектов меняться не будут, и доступ по индексу быстрый

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

lester ★★★★
()

> Абсолютно пофиг на скорость добавления и удаления элементов.

А что выбрать, если то же самое, но требуется динамическое добавление-удаление элементов (пофиг, с какой скоростью... причём добавлять элементы надо только в конец)


std::vector<myClass*>

lester ★★★★
()
Ответ на: комментарий от lester

> тогда уж лучше сразу на Java писать

Если условия позволяют, то лучше писать сразу на CL, зачем Java? Если надо «экономить», то уж лучше на C, зачем С++?

Если писать на C++, то лучше писать как можно более безопастно. А вот когда профайлер покажет, что узкое место это использование boost::shared_ptr (в большинстве реальных программ это маловероятно), вот тогда можно будет подумать об оптимизации.

archimag ★★★
()
Ответ на: комментарий от lester

> std::vector<myClass*>

Ну да, небольшая экономия на smart-указателях приводит к тому, что большинство программистов на C++ начинают допускать ошибки при управлении ресурсами и память течёт. Зато течёт оптимально...

archimag ★★★
()
Ответ на: комментарий от archimag

> Если надо «экономить», то уж лучше на C, зачем С++?

ТС надо ООП как я понял

Если писать на C++, то лучше писать как можно более безопастно


можно писать и безопасно и быстро, если второй пункт не нужен - выбор С++ не оправдан

А вот когда профайлер покажет, что узкое место это использование boost::shared_ptr (в большинстве реальных программ это маловероятно), вот тогда можно будет подумать об оптимизации.


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

lester ★★★★
()
Ответ на: комментарий от archimag

> Ну да, небольшая экономия на smart-указателях приводит к тому, что большинство программистов на C++ начинают допускать ошибки при управлении ресурсами и память течёт. Зато течёт оптимально...

такие программисты на C++ не нужны, лучше их заставить писать на Java и не подпускать к С/С++

lester ★★★★
()
Ответ на: комментарий от lester

> такие программисты на C++ не нужны, лучше их заставить писать

на Java и не подпускать к С/С++


Это философское, в реальном мире они есть и много, уж я то насмотрелся. Тот факт, что в значительном количестве программ на C++ память течёт, как бы широко известен. И если ты работаешь в команде, а не в одиночку, то должен принимать это во внимание. В конце концов, людей обычно нанимаешь не ты, да подобрать нужного уровня специалистов в рамках установленного бюджета бывает затруднительно.

archimag ★★★
()
Ответ на: комментарий от archimag

> Тот факт, что в значительном количестве программ на C++ память течёт, как бы широко известен.

тот факт, что в значительном количестве программ на любом языке есть куча багов и проблем, как бы широко известен

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


Java :) и дешево и уровень не так важен

lester ★★★★
()
Ответ на: комментарий от lester

> можно писать и безопасно и быстро, если второй пункт не нужен

- выбор С++ не оправдан


Хотите сказать, что boost::shared_ptr всегда настолько замедляет работу, что Java становиться быстрее?

в данной задаче нет других узких мест, кроме соб-но работы

с массивами объектов



Я полагаю, что эти объекты некие «сферические кони в вакууме» и работа с ними ничего не стоит и подсчёт ссылок с разыменованием указателя становится главной нагрузкой на системы?

Не имея на руках данных профайлера утверждать что-либо подобное это классический пример преждевременной оптимизации. Но только если память потечёт, то вряд ли программа станет от этого быстрее.

archimag ★★★
()
Ответ на: комментарий от archimag

> Хотите сказать, что boost::shared_ptr всегда настолько замедляет работу, что Java становиться быстрее?

во-первых не надо недооценивать Java, а во-вторых далеко не всегда - но в данной задаче очень вероятно, что так и будет, исходя из ее специфики

Я полагаю, что эти объекты некие «сферические кони в вакууме» и работа с ними ничего не стоит и подсчёт ссылок с разыменованием указателя становится главной нагрузкой на системы?


ТС уже писал о своей задаче - и если алгоритм взаимодействия объектов нельзя изменить, то да - «подсчёт ссылок с разыменованием указателя становится главной нагрузкой», которой можно избежать( которой вообще не должно быть )

Не имея на руках данных профайлера утверждать что-либо подобное это классический пример преждевременной оптимизации.


противиться ненужному замедлению на ровном месте - это не оптимизация, вообще посмотрите типичные библиотеки на С++ - никто не хранит так объекты

Но только если память потечёт, то вряд ли программа станет от этого быстрее.


а еще она упасть может, да, ужас

lester ★★★★
()
Ответ на: комментарий от archimag

> Ну т.е. firefox надо было сразу писать на Java?

а там есть вектора из смарт-птр?

lester ★★★★
()

тупо аналог тупо массива - std::vector

shty ★★★★★
()
Ответ на: комментарий от Obey-Kun

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

потому-что удаление/добавление не сделает указатели «битыми», а указывать они будут на собс-но объекты, потому можно будет отдать указатель и знать, что он не привязан к позиции в контейнере

lester ★★★★
()
Ответ на: комментарий от lester

> во-первых не надо недооценивать Java, а во-вторых далеко не всегда -

но в данной задаче очень вероятно, что так и будет, исходя из ее

специфики



Из какой специфики? Я там ранее в обсуждении про std::vector помню было сказано, что на фоне математики разница скорости доступа по индексу для std::vector или для std::list будет не критична. И вы предлагаете экономить на спичках?

противиться ненужному замедлению на ровном месте -

это не оптимизация



Ненужному? Гарантированная защита от утечек памяти это не нужно?

вообще посмотрите типичные библиотеки на С++ -

никто не хранит так объекты



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

Ну т.е. firefox надо было сразу писать на Java?

а там есть вектора из смарт-птр?


Уж лучше бы были, а то его способность пожирать память стала уже легендарной. И между прочим, эта сволочь начинает таким образом замедлять всю систему. Одна из причин, почему я в итоге ушёл на Chromium.

archimag ★★★
()
Ответ на: комментарий от shty

> эсли юзаешь Qt - QVector

в ядре программы (где математика) Qt не юзаю

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от archimag

> И вы предлагаете экономить на спичках?

Ненужному? Гарантированная защита от утечек памяти это не нужно?


Java

Но то библиотеки, они должны быть максимально быстрыми. Мы же говорим о разработке конкретного приложения.


оно не должно быть быстрым?

Одна из причин, почему я в итоге ушёл на Chromium.


«а там есть вектора из смарт-птр?»

lester ★★★★
()
Ответ на: комментарий от lester

> Java

Ну что-ты заладил Java да Java. Кроме прочего, скорость это не единственная причина использования C++.

оно не должно быть быстрым?


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

«а там есть вектора из смарт-птр?»


Не знаю, я его код не смотрел, но он быстрый. И ранее я смотрел другой код от Google - там почти никогда по программе не гуляют голые указатели.

archimag ★★★
()
Ответ на: комментарий от lester

потому-что удаление/добавление не сделает указатели «битыми», а указывать они будут на собс-но объекты, потому можно будет отдать указатель и знать, что он не привязан к позиции в контейнере

Ясно.

Вообще, тут подумалась такая штука. Работа всегда выполняется таким образом:

1. Юзер рисует на поле ячейки. Каждая ячейка пока что — айтем сцены типа qfgui::Cell. который знает только о своих координатах и размерах. При этом автоматически создаётся объект типа qfcore::Cell, который знает только и своих размерах и имеет некоторые незаполненные поля.

2. Юзер создаёт библиотеку типов свойств ячеек. Тип ячеек содержит их физические свойства (например, теплоёмкость и теплопроводность), а также цвет, которым проводится визуализация.

3. Юзер выделяет группы ячеек и присваивает им типы

4. Юзер выделяет группы ячеек и даёт им прочие свойства напрямую — те свойства, которые не требуют типизации. Например, температуру.

5. Юзер запускает модель. При этом блокируется любые изменения поля.

6. Модель считается. Юзер может остановить рассчёт и что-то изменить, после чего снова её запустить.

Так вот мне кажется, что изначально объекты типа qfcore::Cell стоит хранить в list (так как заранее количество ячеек, которые создасть пользователь, неизвестно), а при переходе из 4 в 5 перенести это тупо массив (new), изменяя ссылки в qfgui::Cell на новые.

Когда расчёты окончатся, сделать обратное преобразование (из тупо массива в list), так как юзер наверняка будет менять ячейки.

Вариант, который мне меньше нравится — сначала хранить всё в куче (все свойства в qfgui::Cell), а при начала рассчёта выделять те свойства, которые нужны модели в qfcore::Cell, а в qfgui::Cell создавать ссылку на него.

Если тут идеологическая ошибка — поправьте. Но стоить иметь в виду, что архиважна скорость копирования и пробегания по всем qfcore::cell во время рассчёта.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от archimag

> Ну что-ты заладил Java да Java. Кроме прочего, скорость это не единственная причина использования C++.

какие еще?

Оптимизация нужна только в критических местах, а не по всей программе.


тут именно так

начинаешь задаваться вопросом - кто в конце концов должен удалить этот объект?


бедные-бедные программисты на С, про тех кто пишет на asm вообще лучше не вспоминать

Не знаю, я его код не смотрел, но он быстрый.


а что из того, что ты смотрел и быстрое, и требует оптимизации( браузеры, например, очень критичны к ней ) и использует «твой» подход?

И ранее я смотрел другой код от Google - там почти никогда по программе не гуляют голые указатели.


а я смотрел другой код «от Google» - он вообще на Go написан( намек, что в гугле не один человек работает, и что задачи бывают разные )

lester ★★★★
()
Ответ на: комментарий от Obey-Kun

в связи с вышесказанным, думается мне, кажется вообще лучше так сделать:

в qfgui::Cell имеется qfcore::Cell *m_cell

в конструкторе qfgui::Cell — m_cell = new qfCoreCell.

при запуске модели посчитать количество qfgui::Cell, создать new массив типа qfcore::Cell и перекопировать туда все m_cell, проводя delete m_cell и заменяя ссылки на новые.

при остановке модели проводить обратное преобразование.

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

недостатков не вижу, так что если мне никто на них не укажет, так и сделаю

PS: алсо, насчёт типов... наверное, в qfcore::Cell в угоду скорости лучше не делать типы и указатели на них в каждой ячейке, а хранить свойства каждой ячейке в ней самой — пусть данные дублируются и это занимает больше памяти, зато это положительно влияет на скорость. Или нет? Тип свойств грунта содержит с пяток даблов и всё.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

ещё вариант — удобства для (ради одного только size(), например) использовать vector и резервировать место заранее.

так ведь не должны сбиваться указатели при заполнении (так как размер не меняется), я прав?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от lester

> какие еще?

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

бедные-бедные программисты на С


Ты знаешь какой подход используют бедные программисты на C для управления ресурсами в таких приложениях как Apache или nginx?

а что из того, что ты смотрел и быстрое, и требует оптимизации(

браузеры, например, очень критичны к ней )


и использует «твой» подход?



Автор пишет браузер? Я правильно понимаю, что разработчики boost просто тупят и им лучше бы писать на Java?

archimag ★★★
()
Ответ на: комментарий от archimag

> На моей предыдущей работе пишут одну софтину, обновления для которой распространяют на несколько тысяч филиалов и С++, например, позволяет максимально упростить именно задачу распространения, которая в пределах нашей Родины из-за плохих каналов является весьма критичной

это смешно

Ты знаешь какой подход используют бедные программисты на C для управления ресурсами в таких приложениях как Apache или nginx?


да, знаю и сам пользуюсь, а что?

Автор пишет браузер?


если речь про ТС - то разве циклы, которые у него будут отрабатывать, недостаточно критичны к скорости?

Я правильно понимаю, что разработчики boost просто тупят и им лучше бы писать на Java?


разработчики boost вообще много мусора написали, чего стоит только «реализация» лямбд

lester ★★★★
()
Ответ на: комментарий от archimag

скорость это не единственная причина использования C++

опа! а какая ещё? садо-мазо?

shty ★★★★★
()
Ответ на: комментарий от archimag

На C было бы ещё проще, только это уж слишком большой напряг.

взаимоисключающие параграфы

shty ★★★★★
()
Ответ на: комментарий от lester

>> Если надо «экономить», то уж лучше на C, зачем С++?

ТС надо ООП как я понял

Вы так говорите, будто на Си нельзя писать в ООП :)

А вообще, по опыту предыдущих тем, ТС просто использует Qt

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

> Вы так говорите, будто на Си нельзя писать в ООП :)

ООП бывает разный, все-таки если на уровне языка есть хоть частичная поддержка - это уже большое подспорье

lester ★★★★
()
Ответ на: комментарий от yoghurt

> А вообще, по опыту предыдущих тем, ТС просто использует Qt

Гуй на Qt. Там скорость не критична. В ядре, где хранятся только необходимые для рассчётов данные, скорость критичная и от Qt ни слуху, ни духу.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от lester

> разработчики boost вообще много мусора написали

А, я понял, и члены комитета по стандартизации C++ очевидно тоже, те ещё специалисты, что за жизнь пошлна, настоящие эксперты по C++ остались только на ЛОР, куда катиться мир?

archimag ★★★
()
Ответ на: комментарий от archimag

> А, я понял, и члены комитета по стандартизации C++ очевидно тоже, те ещё специалисты, что за жизнь пошлна, настоящие эксперты по C++ остались только на ЛОР, куда катиться мир?

но вот - перевел все на личности, значит нет аргументов? если ты не в курсе - boost это больше «полигон для испытаний», и да - ты считаешь, что лямбды в бусте это не мусор? даже несмотря на готовую «родную» реализацию в gcc и msvc?

lester ★★★★
()
Ответ на: комментарий от yoghurt

Кстати, насчёт Си и ООП. Недавно делал одну задачу, вы мне скажите, это ООП-style или не очень?

/**
 * Точка (геометрическая).
 */
typedef struct {
    /// Координата x
    double x;
    /// Координата y
    double y;
} Point;

/**
 * Зафиксированное измерение.
 */
typedef struct {
    /// Измеренная разность потенциалов delta U
    double u;
    /// Рассчитанное кажущееся сопротивление
    double r;
} Measure;

/**
 * Профиль.
 */
typedef struct {
    /// Указатель на массив измерений.
    Measure *measures;
} Section;

/**
 * Планшет.
 */
typedef struct {
    /// Верхняя левая точка
    Point top_left;
    /// Первый питающий электрод
    Point A;
    /// Второй питающий электрод
    Point B;
    /// Указатель на массив профилей.
    Section *sections;
    /// Шаг между точками измерений по профилям.
    double measure_step;
    /// Расстояние между профилями.
    double section_step;
    /// Количество профилей
    unsigned int num_of_sections;
    /// Количество измерений в каждом профиле
    unsigned int num_of_measures_in_section;
    /// Сила тока
    double I;
} Plat;

/* Размеры планшета (по точкам измерений): */
/// Ширина планшета
double width(const Plat* plat);
/// Высота планшета
double height(const Plat* plat);

/* Углы планшета (по точкам измерений): */
/// Нижний левый угол планшета
Point bottomLeft(const Plat* plat);
/// Верхний правый угол планшета
Point topRight(const Plat* plat);
/// Нижний правый угол планшета
Point bottomRight(const Plat* plat);

/* .... */

кусок кода

if ( /* первый выше */
    plat2->top_left.y >= bottomLeft(plat1).y &&
    plat1->top_left.y > plat2->top_left.y &&
    bottomLeft(plat2).y < bottomLeft(plat1).y
   ) {
    start_section_num1 = (int) ( plat1->top_left.y - plat2->top_left.y ) / plat1->section_step;
    end_section_num2 = (int) ( plat2->top_left.y - bottomLeft(plat1).y ) / plat1->section_step;
} else if ( /* первый ниже */
    plat1->top_left.y >= bottomLeft(plat2).y &&
    plat2->top_left.y > plat1->top_left.y &&
    bottomLeft(plat1).y < bottomLeft(plat2).y
    ) {
    start_section_num2 = (int) ( plat2->top_left.y - plat1->top_left.y ) / plat1->section_step;
    end_section_num1 = (int) ( plat1->top_left.y - bottomLeft(plat2).y ) / plat1->section_step;
} else {
    // или общих точек нет, или один планшет лежит внутри другого
    printf("Either no lapping points or one plat is inside other plat!\n");
    exit(1);
}

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

если это и есть использование C для ООП, то я не вижу смысла в таком бдсм (а писал именно на С, так как попросили на С)

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от lester

> но вот - перевел все на личности

Ну а что прикажешь делать, если ты отрицаешь накопленный «миллионами» опыта программирования на C++ (в частности, наиболее эффективный метод защиты от утечек памяти), подвергаешь сомнению квалификацию ведущих специалистов по C++ и берёшься судить о критичных с точки зрения производительности участков программы не имея на руках показаний профайлера? Попахивает неадекватом.

И вообще, эта мысль, что любая программа на С++ должна быть быстрой настолько, насколько это вообще возможно, иначе лучше писать на Java, та ещё... С++ даёт хороший уровень контроля над производительностью и мы можем использовать более низкоуровневые средства так, где это действительно необходимо, и более высокоуровневые для всего остального.
Иначе и смысла то в С++ (ну кроме legacy) особо нет, ведь голый C таки будет быстрее.

archimag ★★★
()
Ответ на: комментарий от archimag

> Ну а что прикажешь делать, если ты отрицаешь накопленный «миллионами» опыта программирования на C++ (в частности, наиболее эффективный метод защиты от утечек памяти)

никогда я не отрицал его, я против его использования в данном случае - и аргументировал позицию

берёшься судить о критичных с точки зрения производительности участков программы не имея на руках показаний профайлера?


профайлер не панацея - опытный программист и так тебе скажет, что в данном участке кода плохо и неоптимально

Попахивает неадекватом.


проветривать надо

С++ даёт хороший уровень контроля над производительностью и мы можем использовать более низкоуровневые средства так, где это действительно необходимо


возьми задачу ТС - ты сможешь там сделать такое разделение в рамках описанного в начале топика?

Иначе и смысла то в С++ (ну кроме legacy) особо нет, ведь голый C таки будет быстрее.


не всегда и не везде

lester ★★★★
()
Ответ на: комментарий от Obey-Kun

С очень большой натяжкой. Plain-реализация, так сказать

Этот код можно сделать изящнее, более заООПить, так сказать: определить мультиметоды higher (Object, Object) и lower (Object, Object), которые будет работать как с Point'ами, так и с Plat'ами, так и вообще с чем угодно одновременно.

Вот тут, например, написано, как.

yoghurt ★★★★★
()
Ответ на: комментарий от lester

> профайлер не панацея - опытный программист и так тебе скажет,

что в данном участке кода плохо и неоптимально


Сказки. Собственно, в этом суть разногласия. Умные люди утверждают, что только профайлер может показать узкие места. Но некоторые верят в свою способность «видеть узкие места» и предпочитают тратить силы на борьбу с ветряными мельницами.

archimag ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.