Russian Qt Forum
Март 28, 2024, 23:12 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4] 5 6   Вниз
  Печать  
Автор Тема: Современные одномерные и двумерные массивы на C++  (Прочитано 46084 раз)
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #45 : Октябрь 30, 2014, 13:26 »

И вообще, лучше всегда предпочитать более высокий уровень (вектор), ибо работа с ним менее подвержена ошибкам и более понятна. А вот если нужно оптимизировать по скорости, тогда милости просим, делайте все на указателях, но изолируйте этот код и добавьте описание.
Всё правильно. Но выступают не против вектора конкретно, а против его бездумного использования везде и всюду Улыбающийся. Что вектора нужно использовать везде, а "старые" массивы выкинуть на свалку истории. Хотя эти штуки друг другу не мешают, и использовать надо то, что резонно и оптимально в конкретном случае.
Записан

Пока сам не сделаешь...
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #46 : Октябрь 30, 2014, 13:28 »

И вообще, лучше всегда предпочитать более высокий уровень (вектор), ибо работа с ним менее подвержена ошибкам и более понятна. А вот если нужно оптимизировать по скорости, тогда милости просим, делайте все на указателях, но изолируйте этот код и добавьте описание.
Всё правильно. Но выступают не против вектора конкретно, а против его бездумного использования везде и всюду Улыбающийся. Что вектора нужно использовать везде, а "старые" массивы выкинуть на свалку истории. Хотя эти штуки друг другу не мешают, и использовать надо то, что резонно и оптимально в конкретном случае.
Лично я не юзаю сишные массивы. Если изменять не надо и можно вычислить на этапе компиляции - std::array, в противном случае вектор.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
vulko
Гость
« Ответ #47 : Октябрь 30, 2014, 13:31 »

Какая сложность операций? На паре тысяч элементов ты не заметишь разницу по скорости между пушбэком на пустой вектор и первоначальным ресайзом. Если скорость становится более критичной, делаем ресайз изначально.

1. Если делаем ресайз изначально, про пуш бэк забудь.

2. Да, на паре тысяч не заметишь. Но я тут несколько раз автору задавал вопрос, он как бы не заметил... А если пару миллионов вертексов он будет добавлять пуш бэком - что будет?
Да и зависит это от "форс-мажора". К тому же важно что в векторе хранится. Мало ли, захочется какому-нибудь взрослому дяде хранить там структуры на пару сотен байт по значению...

Если этого не хватает, переходим на самописные реализации.

Об чем и речь Подмигивающий
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #48 : Октябрь 30, 2014, 13:33 »

1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. Подмигивающий
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
vulko
Гость
« Ответ #49 : Октябрь 30, 2014, 13:50 »

1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. Подмигивающий

При чем тут reserve?
Ты когда сделаешь ресайз, у тебя push_back будет увеличивать размер контейнера каждый раз, т.е. добавлять новый элемент.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #50 : Октябрь 30, 2014, 13:52 »

Лично я не юзаю сишные массивы. Если изменять не надо и можно вычислить на этапе компиляции - std::array, в противном случае вектор.
std::array - разумная замена сишным массивам. Если компилятор поддерживает С++11. Но некоторым всё еще приходится возиться со старыми Улыбающийся.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #51 : Октябрь 30, 2014, 13:56 »

...и использовать надо то, что резонно и оптимально в конкретном случае.
В данном случае согласен с научным работником. И немало ситуаций где вектор нехорош. Напр вот такое
Код
C++ (Qt)
   std::vector< std::vector<int> > arr( 5 );
 
Но дяди как-то на это не обратили внимания Улыбающийся А по мне так глаз режет
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #52 : Октябрь 30, 2014, 14:12 »

1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. Подмигивающий

При чем тут reserve?
Ты когда сделаешь ресайз, у тебя push_back будет увеличивать размер контейнера каждый раз, т.е. добавлять новый элемент.
Делаешь резерв и пушбэкаешь без перераспределения памяти пока не дойдешь до границы.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
vulko
Гость
« Ответ #53 : Октябрь 30, 2014, 14:18 »

1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. Подмигивающий

При чем тут reserve?
Ты когда сделаешь ресайз, у тебя push_back будет увеличивать размер контейнера каждый раз, т.е. добавлять новый элемент.
Делаешь резерв и пушбэкаешь без перераспределения памяти пока не дойдешь до границы.

Память сожрется сразу. Иногда это может быть минусом.
Не все так прекрасно и безоблачно, как хотелось бы. Везде есть свои плюсы, свои минусы.
Записан
alex312
Хакер
*****
Offline Offline

Сообщений: 606



Просмотр профиля
« Ответ #54 : Октябрь 30, 2014, 15:50 »

Создал небольшой тест:
Код
C++ (Qt)
/*******************************************************************************
*  file    :
*  created : 30.10.2014
*  author  :
*******************************************************************************/

 
#include <iostream>
#include <vector>
#include <array>
#include <chrono>
 
#include <cstdint>
 
using namespace std::chrono;
 
template<class T, uint32_t N >
inline uint32_t ARRAY_SIZE(T (&)[N]) {return N;}
 
static const float g_quad_vertex_buffer_data[] = {
   -1.0f, -1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
   -1.0f,  1.0f, 0.0f,
   -1.0f,  1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
    1.0f,  1.0f, 0.0f,
};
 
static const std::vector<float> v = {
   -1.0f, -1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
   -1.0f,  1.0f, 0.0f,
   -1.0f,  1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
    1.0f,  1.0f, 0.0f,
};
 
static const std::array<float, 18> a = {
   -1.0f, -1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
   -1.0f,  1.0f, 0.0f,
   -1.0f,  1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
    1.0f,  1.0f, 0.0f,
};
 
double make_sum(const float* data, std::size_t sz);
 
template <typename T>
double make_sum_inl(const T& vec)
{
   double res = 0.;
   for(std::size_t i = 0; i < vec.size(); ++i)
       res += vec.at(i);
 
   return res;
}
 
double make_sum_inl(const float* data, std::size_t sz)
{
   double res = 0.;
   for(std::size_t i = 0; i < sz; ++i)
       res += data[i];
 
   return res;
}
 
int main(int argc, char* argv[])
{
   std::cout << "Hello ..." << std::endl;
 
   std::cout << "Sum 1 =  " << make_sum(g_quad_vertex_buffer_data,ARRAY_SIZE(g_quad_vertex_buffer_data)) << std::endl;
   std::cout << "Sum 2 =  " << make_sum(v.data(),v.size()) << std::endl;
 
   static const uint64_t iter_cnt = 100000000;
 
   {
       high_resolution_clock::time_point t1 = high_resolution_clock::now();
       volatile double s;
       const std::size_t add_sz = ARRAY_SIZE(g_quad_vertex_buffer_data);
       for(uint64_t i = 0; i < iter_cnt; i ++)
           s = make_sum(g_quad_vertex_buffer_data, add_sz);
       high_resolution_clock::time_point t2 = high_resolution_clock::now();
 
       std::cout << "C array (noinline)\t ";
       std::cout << duration_cast<nanoseconds>(t2 - t1).count() ;
       std::cout << std::endl;
   }
 
   {
       high_resolution_clock::time_point t1 = high_resolution_clock::now();
       volatile double s;
       for(uint64_t i = 0; i < iter_cnt; i ++)
           s = make_sum(v.data(),v.size());
       high_resolution_clock::time_point t2 = high_resolution_clock::now();
 
       std::cout << "Vector  (noinline)\t " ;
       std::cout << duration_cast<nanoseconds>(t2 - t1).count() ;
       std::cout << std::endl;
   }
 
   {
       high_resolution_clock::time_point t1 = high_resolution_clock::now();
       volatile double s;
       for(uint64_t i = 0; i < iter_cnt; i ++)
           s = make_sum(a.data(),a.size());
       high_resolution_clock::time_point t2 = high_resolution_clock::now();
 
       std::cout << "Array   (noinline)\t " ;
       std::cout << duration_cast<nanoseconds>(t2 - t1).count() ;
       std::cout << std::endl;
   }
//======================================================================================================
 
   {
       high_resolution_clock::time_point t1 = high_resolution_clock::now();
       volatile double s;
       const std::size_t add_sz = ARRAY_SIZE(g_quad_vertex_buffer_data);
       for(uint64_t i = 0; i < iter_cnt; i ++)
           s = make_sum_inl(g_quad_vertex_buffer_data,add_sz);
       high_resolution_clock::time_point t2 = high_resolution_clock::now();
 
       std::cout << "C array (inline)\t " ;
       std::cout << duration_cast<nanoseconds>(t2 - t1).count() ;
       std::cout << std::endl;
   }
 
   {
       high_resolution_clock::time_point t1 = high_resolution_clock::now();
       volatile double s;
       for(uint64_t i = 0; i < iter_cnt; i ++)
           s = make_sum_inl(v);
       high_resolution_clock::time_point t2 = high_resolution_clock::now();
 
       std::cout << "Vector  (inline)\t " ;
       std::cout << duration_cast<nanoseconds>(t2 - t1).count() ;
       std::cout << std::endl;
   }
 
   {
       high_resolution_clock::time_point t1 = high_resolution_clock::now();
       volatile double s;
       for(uint64_t i = 0; i < iter_cnt; i ++)
           s = make_sum_inl(a.data(),a.size());
       high_resolution_clock::time_point t2 = high_resolution_clock::now();
 
       std::cout << "Array   (inline)\t " ;
       std::cout << duration_cast<nanoseconds>(t2 - t1).count() ;
       std::cout << std::endl;
   }
 
   return 0;
}
 
__attribute__((noinline)) double make_sum(const float* data, std::size_t sz)
{
   double res = 0.;
   for(std::size_t i = 0; i < sz; ++i)
       res += data[i];
 
   return res;
}
 
 

Вот вывод программы :
Hello ...
Sum 1 =  0
Sum 2 =  0
C array (noinline) 1062060700
Vector (noinline) 1050060100
Array (noinline) 1181067600
C array (inline) 1262072100
Vector (inline) 805046000
Array (inline) 796045500
Дополнения, конструктивная критика приветствуется.
« Последнее редактирование: Октябрь 30, 2014, 15:58 от Пантер » Записан
vulko
Гость
« Ответ #55 : Октябрь 30, 2014, 16:19 »

Ну для начала неплохо бы сделать код чуть более идентичным Подмигивающий

Цитировать
...
        high_resolution_clock::time_point t1 = high_resolution_clock::now();
        volatile double s;
        const std::size_t add_sz = ARRAY_SIZE(g_quad_vertex_buffer_data);
...


Цитировать
...
        const std::size_t add_sz = ARRAY_SIZE(g_quad_vertex_buffer_data);
        high_resolution_clock::time_point t1 = high_resolution_clock::now();
        volatile double s;
...
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #56 : Октябрь 30, 2014, 18:13 »

Создал небольшой тест:
...
Вот вывод программы :
Код:
Hello ...
C array (noinline) 1062060700
Vector (noinline) 1050060100
Array (noinline) 1181067600
C array (inline) 1262072100
Vector (inline) 805046000
Array (inline) 796045500

Тщательнее надо тестировать. Компилятор когда оптимизирует, иногда чудные вещи выдаёт. Если блоки "C array\Vector\Array" менять местами, то и результаты могут меняться. Первый блок, как-то получается, выполняется дольше. Ну и нужно указывать, на какой платформе, каким компилятором и с какими параметрами оптимизации это собиралось.

В Вашем примере, по большому счёту, тестировалась скорость доступа к элементам массива/вектора по их индексу. Что не очень интересно, т.к. она одинаковая, в пределах погрешности измерения скорости. В моём примере с OpenGL предлагалось замерить скорость создания, заполнения и использования массива внутри функции. Файл с тестом во вложении.

У меня получились такие результаты:
Код:
Hello ...
Sum 1 =  0
Sum 2 =  0
Array   (noinline)       975055800
C array (noinline)       871049800
Vector  (noinline)       1006057600
Array   (inline)         666038100
C array (inline)         656037500
Vector  (inline)         660037700
Array  self (inline)     2067118200
C array self (inline)    2101120100
Vector self (inline)     21511230400

Первые три теста ( Array   (noinline), C array (noinline), Vector  (noinline) ) на самом деле выполняются с одинаковой скоростью, тут глюки замера скорости, о которых выше говорил. В других прогонах она примерно одинаковая. А вот Vector self (inline) выполняется действительно намного дольше.

Собирал в Windows 7 64, mingw g++ 4.8.0, "g++.exe -std=c++11 -O3 test.cpp". Если ещё какие опции компилятора надо включить, предлагайте. Стоит отметить, что MSVC 2012 и меньше такое не собирает, ибо плохо ещё знает C++11.
Записан

Пока сам не сделаешь...
alex312
Хакер
*****
Offline Offline

Сообщений: 606



Просмотр профиля
« Ответ #57 : Октябрь 30, 2014, 18:38 »

Я компилю так:
g++  -Wa,-adhlns=lst/main.lst -flto -O2 -std=gnu++11 -g  -ffunction-sections -fdata-sections -c -o build/main.o src/main.cpp
g++  build/main.o -o bin/test_vec.exe -Wa,-adhlns=lst/main.lst -flto -pthread

А вот Vector self (inline) выполняется действительно намного дольше.
Что естественно. Потому как массив и array создаются на стеке, а вектор лезет в кучу.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #58 : Октябрь 30, 2014, 19:17 »

А вот Vector self (inline) выполняется действительно намного дольше.
Что естественно. Потому как массив и array создаются на стеке, а вектор лезет в кучу.

О том и речь была. Чтобы внутри метода передать массив функции OpenGL вектор на фик не нужен. Ни по смыслу, ни по удобству, ни по скорости. Хотя в других случаях всё может быть совсем наоборот Улыбающийся.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #59 : Октябрь 31, 2014, 09:10 »

Стоит отметить, что MSVC 2012 и меньше такое не собирает, ибо плохо ещё знает C++11.
Ну почему же
Цитировать
вот швейная машинка - почини и строчи сколько хочешь
Всего лишь declspec (вместо attribute) и инициализацию вектора вручную - и все работает.

Дополнения, конструктивная критика приветствуется.
А почему используете цикл for - где же концептуальная общность? Давайте уж лепить все самое новое. И я прилепил
Код
C++ (Qt)
template <typename T>
double make_sum_inl( const T& vec)
{
   double res = 0.;
//    for(std::size_t i = 0; i < vec.size(); ++i)
//       res += vec.at(i);
 
for (auto it : vec)
res += it;
 
   return res;
}
 
И получил
Цитировать
Hello ...
Sum 1 =  0
Sum 2 =  0
C array (noinline)       60000100
Vector  (noinline)       60000100
Array   (noinline)       70000100
C array (inline)         60000100
Vector  (inline)         1312003000
Array   (inline)         70000100
Число итераций пришлось уменьшить в 100 раз (до 1 млн) - иначе не дождесся. Правда в Release все норм (10 млн)
Цитировать
Hello ...
Sum 1 =  0
Sum 2 =  0
C array (noinline)       202001500
Vector  (noinline)       210000300
Array   (noinline)       210000300
C array (inline)         210000300
Vector  (inline)         200000200
Array   (inline)         140000200

Почему-то автоматически полагается что мы на "экологически чистом" ОС, где все работает по последнему слову теории и.т.п. Но в жизни это далеко не всегда так. И за глуповатое (на мой взгляд) стремление обязательно втулить stl приходится платить лазя по кишкам компилятора/IDE/платформы
Записан
Страниц: 1 2 3 [4] 5 6   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.15 секунд. Запросов: 23.