Russian Qt Forum

Программирование => С/C++ => Тема начата: 8Observer8 от Октябрь 29, 2014, 10:28



Название: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 10:28
Привет! Мне надоело объяснять на форумах как надо создавать одномерные и двумерные массивы. Поэтому создаю тему, на которую буду делать ссылки. От вас прошу высказать своё мнение, дополнить, посоветовать, что можно улучшить. Спасибо!

Современные одномерные и двумерные массивы на C++

Одномерные и двумерные динамические массивы на C++ можно создать с помощью std::vector и отказаться от операторов new и delete

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

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector<int> arr( 10, 0 );
 
   return 0;
}
 


Для того чтобы хранить вещественные числа необходимо вместо int написать float, а константу заполнения записать явно, как float: 0.0f

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector<float> arr( 10, 0.0f );
 
   return 0;
}
 


Для того чтобы хранить вещественные числа двойной точности необходимо вместо int написать double, а константу заполнения записать явно, как double: 0.0

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector<double> arr( 10, 0.0 );
 
   return 0;
}
 


После того как мы создали массив мы можем его использовать для хранения чисел. В следующем примере мы присваиваем нескольким элементам массива значения и выводим один их элементов массива на экран:

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
int main()
{
   std::vector<int> arr( 10, 0);
 
   arr[0] = 34;
   arr[1] = 5;
 
   std::cout << arr[0] << std::endl;
 
   return 0;
}
 


Мы можем добавить элемент в массив, тогда увеличится его размер

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
int main()
{
   std::vector<int> arr( 10, 0);
 
   arr[0] = 34;
   arr[1] = 5;
 
   std::cout << "size = " << arr.size() << std::endl; // output: size = 10
 
   arr.push_back( 87 );
   std::cout << arr[10] << std::endl; // output: 87
 
   std::cout << "size = " << arr.size() << std::endl; // output: size = 11
 
   return 0;
}
 


Для того чтобы создать двумерный массив с помощью std::vector необходимо вместо int написать std::vector. Следующая запись означает, что мы создали массив из пяти элементов, каждый из которых - это массив целых чисел:

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector< std::vector<int> > arr( 5 );
 
   return 0;
}
 


Но пока каждый из этих под-массивов нулевой длины. Исправим это:

Код
C++ (Qt)
#include <vector>
 
int main()
{
   const int nrows = 5;
   const int ncols = 3;
 
   std::vector< std::vector<int> > arr( nrows );
 
   for( size_t row = 0; row < nrows; ++row ) {
       arr[row].resize( ncols );
   }
 
   return 0;
}
 
Теперь у нас есть двумерный массив у которого 5 строк и 3 столбца


Присвоим какой-либо ячейке значение и выведем значение этой ячейки на экран:

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
int main()
{
   const int nrows = 5;
   const int ncols = 3;
 
   std::vector< std::vector<int> > arr( nrows );
 
   for( size_t row = 0; row < nrows; ++row ) {
       arr[row].resize( ncols );
   }
 
   arr[4][0] = 87;
 
   std::cout << arr[4][0] << std::endl;
 
   return 0;
}
 


Передача в функцию

Одномерные и двумерные массивы передаются в функцию ссылкой, чтобы передавать адрес объекта, а не копировать целиком. Если не планируется менять значения элементов массива, то добавляется const

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
void show1DArray( const std::vector<int> &arr1D )
{
   std::cout << arr1D[0] << std::endl;
}
 
void show2DArray( const std::vector< std::vector<int> > &arr2D )
{
   std::cout << arr2D[1][1] << std::endl;
}
 
int main()
{
   // 1D array
   std::vector<int> arr1D( 10, 0);
 
   arr1D[0] = 34;
 
   show1DArray( arr1D );
 
   const int nrows = 5;
   const int ncols = 3;
 
   // 2D array
   std::vector< std::vector<int> > arr2D( nrows );
 
   for( size_t row = 0; row < nrows; ++row ) {
       arr2D[row].resize( ncols );
   }
 
   arr2D[1][1] = 5;
 
   show2DArray( arr2D );
 
   return 0;
}
 


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

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
void show1DArray( int *p )
{
   std::cout << p[0] << std::endl;
}
 
int main()
{
   // 1D array
   std::vector<int> arr1D( 10, 0);
 
   arr1D[0] = 34;
 
   show1DArray( arr1D.data() );
 
   return 0;
}
 


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 29, 2014, 11:15
Все конечно классно...

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

Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.


Цитировать
и отказаться от операторов new и delete

чаще всего векторы из int и float создают только студенты.

на практике очень часто приходится создавать контейнеры из указателей на структуры, классы... да даже тупо void*.
отказаться от операторов new и delete врядли получится.
хотя есть вроде аллокаторы, но я ими никогда не пользовался и хз как оно работает.
имхо проще new delete.

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: gil9red от Октябрь 29, 2014, 11:29
... и все равно такие вопросы будут задавать, ибо подобные темы и раньше поднимались, а те кто такие вопросы задают банально не умеют пользоваться гуглом, так чего они будут делать поиск по форуму? :D


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 11:36
Цитировать
чаще всего векторы из int и float создают только студенты.
Как раз таки нет. Они пишут эту дурацкую конструкцию, которой место на свалке:  float *ptrarray = new float [10];

Цитировать
и все равно такие вопросы будут задавать, ибо подобные темы и раньше поднимались, а те кто такие вопросы задают банально не умеют пользоваться гуглом, так чего они будут делать поиск по форуму?
Я тему создал лишь в личных интересах. Для того, чтобы каждый раз не объяснять, а давать ссылку на эту тему


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 11:39
Цитировать
Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.
Что это значит?


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 29, 2014, 11:42
Цитировать
Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.
Что это значит?
Это значит, что нельзя перекидывать такие массивы между модулями (либами), ибо если они собраны разными компиляторами....


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 11:47
Цитировать
Это значит, что нельзя перекидывать такие массивы между модулями (либами), ибо если они собраны разными компиляторами....
Это я не знал. А с std::string такая же фигня?


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Kurles от Октябрь 29, 2014, 11:48
Цитировать
Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.
Что это значит?
Это значит, что нельзя перекидывать такие массивы между модулями (либами), ибо если они собраны разными компиляторами....
Вроде все плюсовые либы компиляторо-зависимы, нет какого-либо стандарта...


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 29, 2014, 11:49
Это я не знал. А с std::string такая же фигня?
Ага. Вообще, любого stl касается. Use Qt, Luke.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 12:10
Цитировать
Вроде все плюсовые либы компиляторо-зависимы, нет какого-либо стандарта...
Все либы, которые я использую, я собирал с помощью Qt из исходников. И это были либы написанные без использования Qt (не мной). За информацию, спасибо

Я сам на практике использую одномерный вектор для хранения координат, а передаю в функции указатель на буфер http://www.cplusplus.com/reference/vector/vector/data/

Можно, конечно, и так передавать: &v[0], но гораздо приятнее так: v.data()

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 29, 2014, 12:12
Цитировать
чаще всего векторы из int и float создают только студенты.
Как раз таки нет. Они пишут эту дурацкую конструкцию, которой место на свалке:  float *ptrarray = new float [10];

почему им место на свалке и чем она дурацкая?


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 12:15
Тем что можно забыть правильно освободить ресурсы, нужно писать лишний код по освобождению ресурсов, а если пользователь вводит и вводит собака, то придётся предусмотреть выделение дополнительных ресурсов


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: kuzulis от Октябрь 29, 2014, 12:18
Блин, форум скатывается в какой-то LOR/BASH.ORG :)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: m_ax от Октябрь 29, 2014, 12:27
Блин, форум скатывается в какой-то LOR/BASH.ORG :)
Меня особенно название темы повеселило: "Современные одномерные и двумерные массивы на C++" Без лишнего пафоса, так..  ;D


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 29, 2014, 12:38
Все либы, которые я использую, я собирал с помощью Qt из исходников. И это были либы написанные без использования Qt (не мной). За информацию, спасибо

Неважно кто собирал, важно не забывать что stl сильно зависит от платформы/компилятора.
И вообще stl штука неоднозначная. Например легко может случиться, что на одной платформе size() будет O(1), а на другой O(N).


Я сам на практике использую одномерный вектор для хранения координат, а передаю в функции указатель на буфер http://www.cplusplus.com/reference/vector/vector/data/

Все операции вставки/извлечения в/из stl контейнера происходят по значению. Т.е. объект копируется.
Гораздо лучше держать контейнер из указателей.

Если не ошибаюсь, stl::vector может фрагментироваться при изменении размера. Либо же при изменении размера он тупо будет заниматься копированием.


Можно, конечно, и так передавать: &v[0], но гораздо приятнее так: v.data()

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

Зачем передавать в функции v.data()?
Можно хранить указатель на вектор и не боятся передавать его в функции. Либо передавать вектор по ссылке... чтобы не испортили по константной ссылке.

В чем конкретно удобство работы с вектором? Для него даже оператор [] перегрузили чтобы он от обычного массива не отличался.
Создавать динамически объекты все равно приходится очень часто. И даже не потому что везде вектора не воткнуть, а просто потому что долго живущие объекты должны жить в куче.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 29, 2014, 12:41
Тем что можно забыть правильно освободить ресурсы, нужно писать лишний код по освобождению ресурсов, а если пользователь вводит и вводит собака, то придётся предусмотреть выделение дополнительных ресурсов

И что, в случае нижеприведенного кода тоже ничего не нужно освобождать?)

Код:
struct DataItem {
   int dataType;
   void *data;
};

typedef vector< vector<DataItem *> > DataItemContainer;

DataItemContainer *allOfMyData;

allOfMyData = new DataItemContainer;

...


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 13:16
Цитировать
Зачем передавать в функции v.data()?
Можно хранить указатель на вектор и не боятся передавать его в функции. Либо передавать вектор по ссылке... чтобы не испортили по константной ссылке.

Хорошо, вот как я делаю:

Код
C++ (Qt)
   std::vector<GLfloat> m_vertices;
   std::vector<GLfloat> m_textures;
   std::vector<GLuint> m_indices;
 
   // ...
 
   m_vertices.push_back( -50.0f );    //X
   m_vertices.push_back( -50.0f );    //Y
   m_vertices.push_back( 0.0f );      //Z
 
   m_vertices.push_back( 50.0f );     //X
   m_vertices.push_back( -50.0f );    //Y
   m_vertices.push_back( 0.0f );      //Z
 
   m_vertices.push_back( 50.0f );     //X
   m_vertices.push_back( 50.0f );     //etc..
   m_vertices.push_back( 0.0f );
 
   // ...
 
   glVertexPointer( 3, GL_FLOAT, 0, m_vertices.data() );
   glTexCoordPointer( 2, GL_FLOAT, 0, m_textures.data() );
   // ...
 

glVertexPointer это функция из OpenGL. Она принимает указатель на GLfloat (GLfloat - это typedef для float). Первый параметр у неё - это по сути количество столбцов. Для glTexCoordPointer - так же

Пойдёт, как ответ на вопрос"Зачем передавать в функции v.data()?"?


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: m_ax от Октябрь 29, 2014, 13:19
Цитировать
Неважно кто собирал, важно не забывать что stl сильно зависит от платформы/компилятора.
И вообще stl штука неоднозначная. Например легко может случиться, что на одной платформе size() будет O(1), а на другой O(N).
Может отличаться внутренняя реализация stl, но стандарту она должна соответствовать.. Я сейчас не говорю о "самом строгом" MSVC.. А приведённый пример с size - касается, например, списка (std::list), но в стандарте C++98 так и говориться: Complexity: Up to linear.
Т.е. никаких непредсказуемых ситуаций) (про MSVC опять молчу)

Цитировать
Все операции вставки/извлечения в/из stl контейнера происходят по значению. Т.е. объект копируется.
 
Нет, в с++11 не всегда..

Цитировать
Гораздо лучше держать контейнер из указателей.
Аха... особенно вектор)

Цитировать
В чем конкретно удобство работы с вектором? Для него даже оператор [] перегрузили чтобы он от обычного массива не отличался.
Да хотя бы из-за того, что он знает свой размер.. Может динамически изменяться, имеет оператор присваивания и конструктор копирования, а в с++11 еще и соответствующие move оператор и конструктор..  У вас какое то поверхностное представление о stl..

Цитировать
Создавать динамически объекты все равно приходится очень часто. И даже не потому что везде вектора не воткнуть, а просто потому что долго живущие объекты должны жить в куче.
Это вообще бред какой то..

 
 

    


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 29, 2014, 13:50
Может отличаться внутренняя реализация stl, но стандарту она должна соответствовать.. Я сейчас не говорю о "самом строгом" MSVC.. А приведённый пример с size - касается, например, списка (std::list), но в стандарте C++98 так и говориться: Complexity: Up to linear.
Т.е. никаких непредсказуемых ситуаций) (про MSVC опять молчу)
Ну зачем молчать про MSVC. Есть те кто пользуют stl и MSVC.

Цитировать
Цитировать
Все операции вставки/извлечения в/из stl контейнера происходят по значению. Т.е. объект копируется.
 
Нет, в с++11 не всегда..
 
с++11 кроме gcc (начиная с определенной версии) кто ещё поддерживает?


Цитировать
Цитировать
Гораздо лучше держать контейнер из указателей.
Аха... особенно вектор)
почему нет? чем вектор из указателей плох?

Цитировать
Да хотя бы из-за того, что он знает свой размер.. Может динамически изменяться, имеет оператор присваивания и конструктор копирования, а в с++11 еще и соответствующие move оператор и конструктор..  У вас какое то поверхностное представление о stl..
размер да, неоспоримое преимущество вектора.
при изменении размера вектора он копируется в новое место или фрагментируется?
с++11 как уже говорил кроме gcc никто толком и не старается соответствовать.
move оператор не для вектора придумывали. вектор можно хоть memcpy скопировать. это преимущество скорее для других контейнеров.

Цитировать
Цитировать
Создавать динамически объекты все равно приходится очень часто. И даже не потому что везде вектора не воткнуть, а просто потому что долго живущие объекты должны жить в куче.
Это вообще бред какой то..   
Бред это писать что современный массив это вектор, а классический массив это пережиток прошлого.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 29, 2014, 14:00
Цитировать
Зачем передавать в функции v.data()?
Можно хранить указатель на вектор и не боятся передавать его в функции. Либо передавать вектор по ссылке... чтобы не испортили по константной ссылке.

Хорошо, вот как я делаю:

Код
C++ (Qt)
   std::vector<GLfloat> m_vertices;
   std::vector<GLfloat> m_textures;
   std::vector<GLuint> m_indices;
 
   // ...
 
   m_vertices.push_back( -50.0f );    //X
   m_vertices.push_back( -50.0f );    //Y
   m_vertices.push_back( 0.0f );      //Z
 
   m_vertices.push_back( 50.0f );     //X
   m_vertices.push_back( -50.0f );    //Y
   m_vertices.push_back( 0.0f );      //Z
 
   m_vertices.push_back( 50.0f );     //X
   m_vertices.push_back( 50.0f );     //etc..
   m_vertices.push_back( 0.0f );
 
   // ...
 
   glVertexPointer( 3, GL_FLOAT, 0, m_vertices.data() );
   glTexCoordPointer( 2, GL_FLOAT, 0, m_textures.data() );
   // ...
 

glVertexPointer это функция из OpenGL. Она принимает указатель на GLfloat (GLfloat - это typedef для float). Первый параметр у неё - это по сути количество столбцов. Для glTexCoordPointer - так же

Пойдёт, как ответ на вопрос"Зачем передавать в функции v.data()?"?

Я не совсем верно сформулировал мысль видимо...

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

Да, где-то он упрощает жизнь. А где-то нет. Но не стоит забывать что это контейнер. И не надо называть его массивом.

П.с. например есть файл на диске, в котором 2 000 000 вертексов. Неужели нужно их каждый добавить в вектор а потом отдать с помощью v.data()? или все же лучше обычный массив GLFloat'ов создать?)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 14:10
Можно полностью отказаться от классических статических и динамических массивов и заменить их std::vector. Если у вас есть либа написанная не на Qt (а так чаще всего и будет), а на STL, то там функции, скорее всего, будут принимать в качестве параметра указатель. Вот тут можно использовать vec.data() и нет проблем. Ещё раз повторю моё мнение, что про классические статические и динамические массивы можно забыть, они устарели и везде использовать std::vector

Цитировать
П.с. например есть файл на диске, в котором 2 000 000 вертексов. Неужели нужно их каждый добавить в вектор а потом отдать с помощью v.data()? или все же лучше обычный массив GLFloat'ов создать?)
Обычный массив в топку! Можно сделать vec.resize( сколько_нужно );

Используя С++11, можно вообще никогда не писать new и delete. Для создания объектов из кучи есть std::make_shared (http://www.cplusplus.com/reference/memory/make_shared/) (в программе может быть несколько ссылок на объект). А в C++14 появился std::make_unique (http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) (одна ссылка на объект)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 29, 2014, 14:22
Обычный массив в топку! Можно сделать vec.resize( сколько_нужно );

Используя С++11, можно вообще никогда не писать new и delete. Для создания объектов из кучи есть std::make_shared (http://www.cplusplus.com/reference/memory/make_shared/) (в программе может быть несколько ссылок на объект). А в C++14 появился std::make_unique (http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) (одна ссылка на объект)

А ничё что vector.resize() это О(n)?

Никогда не писать new и delete это как? Все само создастся?)))
Классы тоже будешь в вектор добавлять, чтобы ни в коем случае не писать самому new и delete? :))

Короче прекрати нести чушь!

Ну а стандарту с++11 далеко не все следуют.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 29, 2014, 18:05
Ещё раз повторю моё мнение, что про классические статические и динамические массивы можно забыть, они устарели и везде использовать std::vector

В рамку и на стенку :). Скотт Мейерс и то скромнее высказывается (http://habrahabr.ru/company/yandex/blog/241601/).

"Классические статические и динамические массивы" и std::vector никак друг другу не мешают. Просто надо знать и понимать, что и в каких случаях лучше использовать. И чтобы подобному учить других, самому знать об этом нужно очень хорошо.

Например, даже современному OpenGL все эти std::vector совершенно до лампочки, он спокойно кушает старые дедовские статические и динамические массивы :).


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 29, 2014, 22:27
Скотта Майерса читаю и прислушиваюсь к нему. Но я пытаюсь всегда своими мозгами пользоваться, а в слепую стараюсь никому не доверять

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

Цитировать
Например, даже современному OpenGL все эти std::vector совершенно до лампочки, он спокойно кушает старые дедовские статические и динамические массивы
Ну и что. Мы спокойно можем работать с std::vector, а функциям OpenGL передавать указатель на буфер vec.data()

Цитировать
А ничё что vector.resize() это О(n)?
Я привёл этот пример, как эквивалент статического массива. В том смысле, что всё равно вы не сможете создать большой статический массив в стеке, и здесь в vector.resize( n ) подразумевается небольшое число n. Тем более что если мы взяли память из кучи и нам её не хватило, то придётся запрашивать бОльшей буфер с помощью new, а потом копировать данные из старого массива в новый. И врядли мы напишем более эффективную версию, чем vec.push_back()

Статический массив
Код
C++ (Qt)
int arr[10]
 

Заменяем на:
Код
C++ (Qt)
std::vector<int> arr(10);
 

Или на это:
Заменяем на:
Код
C++ (Qt)
std::vector<int> arr;
arr.resize( 10 );
 

Цитировать
Никогда не писать new и delete это как? Все само создастся?)))
Классы тоже будешь в вектор добавлять, чтобы ни в коем случае не писать самому new и delete?

А вот так:
Код
C++ (Qt)
#include <iostream>
#include <memory>
 
struct Person
{
   std::string firstName;
   std::string lastName;
};
 
int main()
{
   // Create object
   auto p = std::make_shared<Person>();
 
   // Use object
   p->firstName = "Ivan";
   std::cout << p->firstName << std::endl;
 
   return 0;
}
 

Вместо этого:
Код
C++ (Qt)
#include <iostream>
 
struct Person
{
   std::string firstName;
   std::string lastName;
};
 
int main()
{
   // Create object
   Person *p = new Person;
 
   // Use object
   p->firstName = "Ivan";
   std::cout << p->firstName << std::endl;
 
   // Delete object
   delete p;
 
   return 0;
}
 


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 09:55
Я привёл этот пример, как эквивалент статического массива. В том смысле, что всё равно вы не сможете создать большой статический массив в стеке, и здесь в vector.resize( n ) подразумевается небольшое число n. Тем более что если мы взяли память из кучи и нам её не хватило, то придётся запрашивать бОльшей буфер с помощью new, а потом копировать данные из старого массива в новый. И врядли мы напишем более эффективную версию, чем vec.push_back()

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


Цитировать
Тем более что если мы взяли память из кучи и нам её не хватило, то придётся запрашивать бОльшей буфер с помощью new, а потом копировать данные из старого массива в новый.
А вектор наверное работает магическим образом!
Не вызывает new и уж тем более не копирует память при ресайзе...))))
Вектор работает точно также.
А если вектор из указателей, то и за памятью придется следить.


Цитировать
В том смысле, что всё равно вы не сможете создать большой статический массив в стеке
При чем тут я? Никто не может. Так мир устроен.
Вектор свои данные хранит в куче, а на стэке живет лишь сам объект.
Так что ресайз вектора ничуть не быстрее new[] + copy!


Цитировать
И врядли мы напишем более эффективную версию, чем vec.push_back()

Пожалуйста, нижеприведенный аналог работает быстрее!
Код:
data[pos] = dt;


Цитировать
А вот так:
***
Вместо этого:

Всегда нравились дурацкие примеры...

Никто никогда так не делает в жизни!
А если кто-то так делает, то его нужно бить по голове.

Потому что вызов Person *p = new Person, подразумевает что этот объект не будет в конце этой функции удален.
Если же объект используется в рамках одной функции, то писать нужно Person p;

Цитировать
Код:
    // Create object
    Person *p = new Person;
 
    // Use object
    p->firstName = "Ivan";
    std::cout << p->firstName << std::endl;
 
    // Delete object
    delete p;


С++11 стандарты, как я уже не раз отмечал, имеет смысл использовать только если все это будет компилироваться в gcc начиная с некоей версии.
А что делать если нужно пользовать msvsc?
Если не хочется париться по поводу управления памятью, лучше простой перейти на жабу. Да и с кроссплатформенностью там куда лучше.


Цитировать
Скотта Майерса читаю и прислушиваюсь к нему. Но я пытаюсь всегда своими мозгами пользоваться, а в слепую стараюсь никому не доверять
Ну так и не надо слепо верить в с++11 стандарты.
И думать нужно головой, а не тупо советовать всем использовать всегда и везде вектор, потому что это стильно, модно, молодежно.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Igors от Октябрь 30, 2014, 10:35
Попробуем сделать это интересным

!)
Они пишут эту дурацкую конструкцию, которой место на свалке:  float *ptrarray = new float [10];
Эта "дурацкая" конструкция легко может оказаться выгоднее чем вот эта
Код
C++ (Qt)
   std::vector< std::vector<int> > arr( 5 );
 
В последней есть весьма существенный недостаток. Какой?

2) Удалить массив из кучи - просто delete, а вот как освободить память занимаемую вектором (не создавая новой переменной) ?

3) Какие действия (примерно) производятся при обращении к вектору, и насколько они могут снизить производительность в Debug? Да, и не надо делать вид что MSVC якобы "не существует".

4) Корректно ли это?
Код
C++ (Qt)
int * a = &vec[0];
 

5) Какая основная причина вынуждающая использовать вместо вектора др контейнеры? Также почему часто либы используют свой класс вместо std::vector?

---
Для меня нормально что если человек написал статью, то такие квешнзы для него - семечки, да еще он расскажет кучу интересного, о чем я и не подозревал !  :)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 10:49
Удалить массив из кучи - просто delete, а вот как освободить память занимаемую вектором (не создавая новой переменной)

Просто delete vectorPointer; как раз таки удалит вектор, а для удаления элементов вектора есть vector->clear();
Ну а если вектор создавался на стэке, то и удалять его не нужно, сам удалится.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 30, 2014, 10:51
а для удаления элементов вектора есть vector->clear();
Это удалит элементы, но не освободит память. ;)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: kamre от Октябрь 30, 2014, 11:04
а для удаления элементов вектора есть vector->clear();
Это удалит элементы, но не освободит память. ;)
Тогда позвать еще shrink_to_fit (http://www.cplusplus.com/reference/vector/vector/shrink_to_fit/).


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 11:08
а для удаления элементов вектора есть vector->clear();
Это удалит элементы, но не освободит память. ;)

vector->clear();
vector->resize(0); // или resize(1)

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 30, 2014, 12:22
Хорошо, вы знаете и понимаете, тогда приведите несколько убедительных примеров. Где лучше применять вектор, а где статический и динамический массивы. Я пока своими глазами не увижу, не поверю

Цитировать
Например, даже современному OpenGL все эти std::vector совершенно до лампочки, он спокойно кушает старые дедовские статические и динамические массивы
Ну и что. Мы спокойно можем работать с std::vector, а функциям OpenGL передавать указатель на буфер vec.data()

Пример с OpenGL вполне самодостаточен, как и с другими Сишными библиотеками. Да и WinApi тоже. В общем случае функции, которые получают на вход указатель на массив заданного размера и типа данных.

Кусок кода для OpenGL:
Код
C++ (Qt)
// The fullscreen quad's FBO
GLuint quad_VertexArrayID;
glGenVertexArrays(1, &quad_VertexArrayID);
glBindVertexArray(quad_VertexArrayID);
 
static const GLfloat 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,
};
 
GLuint quad_vertexbuffer;
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
 

Сделайте аналог g_quad_vertex_buffer_data на std::vector, заполните его данными, и сравните быстродействие этих операций со старым и ненужным массивом :).


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: alex312 от Октябрь 30, 2014, 12:24
То что вектор умеет увеличиваться в размерах автоматом, это может и плюс, когда нужно 100 элементов добавить. А если вертексов пару миллионов? Ты попробуй сперва код такой напиши, и посмотрим сколько времени уйдет тупо на ресайз вектора.
Ну и сколько времени уйдет на ресайз вектора? Приведи более быстрый вариант.

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

Цитировать
И врядли мы напишем более эффективную версию, чем vec.push_back()

Пожалуйста, нижеприведенный аналог работает быстрее!
Код:
data[pos] = dt;
Аналог !?

А что делать если нужно пользовать msvsc?
Страдать молча.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: alex312 от Октябрь 30, 2014, 12:37
Сделайте аналог g_quad_vertex_buffer_data на std::vector, заполните его данными, и сравните быстродействие этих операций со старым и ненужным массивом :).
Вот я накидал аналог, если не трудно потестируйте. (правда я не компелировал, но должно работать)
Код
C++ (Qt)
// The fullscreen quad's FBO
GLuint quad_VertexArrayID;
glGenVertexArrays(1, &quad_VertexArrayID);
glBindVertexArray(quad_VertexArrayID);
 
typedef std::vector<float> test_container ;
//typedef std::array<float,18> test_container ;
 
static const test_container 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,
};
 
GLuint quad_vertexbuffer;
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, g_quad_vertex_buffer_data.size(), g_quad_vertex_buffer_data.data(), GL_STATIC_DRAW);


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 30, 2014, 12:42
Вот я накидал аналог, если не трудно потестируйте. (правда я не компелировал, но должно работать)

А Вы таки скомпелируйте и потестируйте :). Код OpenGL можно убрать, оставить только создание и заполнение массива/вектора.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: alex312 от Октябрь 30, 2014, 12:49
А Вы таки скомпелируйте и потестируйте :). Код OpenGL можно убрать, оставить только создание и заполнение массива/вектора.
Нет уж. Это ж ты заявляешь что код с вектором капец как неоптималет, доказывай.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 12:57
То что вектор умеет увеличиваться в размерах автоматом, это может и плюс, когда нужно 100 элементов добавить. А если вертексов пару миллионов? Ты попробуй сперва код такой напиши, и посмотрим сколько времени уйдет тупо на ресайз вектора.
Ну и сколько времени уйдет на ресайз вектора? Приведи более быстрый вариант.
Верхняя граница - O(n)
Зачем мне приводить более быстрый вариант? Я вообще тут за вектор не агитирую если что!

Если совсем упирается в постоянные ресайзы, лучшей перейти на другой контейнер. Есть реализации вектора с фрагментированием. При этом правда собрать буфер типа vector.data() займет поболее времени... но тут из 2-х зол выбирают меньшее.


Цитировать
И врядли мы напишем более эффективную версию, чем vec.push_back()
Пожалуйста, нижеприведенный аналог работает быстрее!
Код:
data[pos] = dt;
Аналог !?

А чем не аналог? Вообще в большинстве случаев размер вектора можно вычислить заранее. А если нельзя... часто берут другие контейнеры.

Ну и опять же вернемся к контексту дискуссии.

Автор привел пример, где он добавил пару-тройку вертексов в контейнер (vector.push_back(val)).
Поскольку push_back увеличивает размер вектора, то получается заранее сделать resize и не терять время на ненужные копирования и ресайзы уже не получится.

А если есть пара миллионов вертексов? Итог думаю вполне понятен.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 30, 2014, 12:59
Как-то все начали наезжать на ресайзы вектора... А как вы стандартные массивы ресайзить собрались? О_о


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Igors от Октябрь 30, 2014, 13:08
Вот я накидал аналог, если не трудно потестируйте. (правда я не компелировал, но должно работать)
Дело здесь не в скорости. Зачем мы создавали вектор если, в данном случае, не собирались использовать никаких его выгод? Объявляя массив мы четко заявляем - пополнять не будем, или будем пере-создавать явно. Это важно для понимания текста др программистом. Делая вектор "на всякий случай" мы эту ясность теряем. Да и вообще, посмотрим как делают люди
Код
C++ (Qt)
 
// QHash.cpp
     if (numBuckets) {
       QT_TRY {
           d->buckets = new Node *[numBuckets];
       } QT_CATCH(...) {
 
Оба-на! А чего же не QVector? Ведь он, якобы, "всегда лучше"  :)

Страдать молча.
С какой это стати? Проблемы совместимости и конкретной реализации никто не отменял. Вообще кто знает, а вдруг std - тупиковая ветвь эволюции?  :)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 30, 2014, 13:10
Да, есть еще std::array.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 30, 2014, 13:12
Вот я накидал аналог, если не трудно потестируйте. (правда я не компелировал, но должно работать)
...
Нет уж. Это ж ты заявляешь что код с вектором капец как неоптималет, доказывай.

А Вы не накидывайте :). Особенно то, что невооружённым взглядом видно, что не скомпилируется.

Изначально я обращался к автору темы. Если Вы предлагаете вариант реализации, то объясните, по каким критериям оно лучше приведённого в моём примере. А тестировать будут те, кому это действительно интересно.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 30, 2014, 13:12
И вообще, лучше всегда предпочитать более высокий уровень (вектор), ибо работа с ним менее подвержена ошибкам и более понятна. А вот если нужно оптимизировать по скорости, тогда милости просим, делайте все на указателях, но изолируйте этот код и добавьте описание.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: alex312 от Октябрь 30, 2014, 13:18

Верхняя граница - O(n)
Отлично, и сколько будет О(n) при n=0 ?

Зачем мне приводить более быстрый вариант? Я вообще тут за вектор не агитирую если что!
Ну, если ты что-то утверждаешь, то это надо агрументировать. А просто так языком махать может каждый.

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

Автор привел пример, где он добавил пару-тройку вертексов в контейнер (vector.push_back(val)).
Поскольку push_back увеличивает размер вектора, то получается заранее сделать resize и не терять время на ненужные копирования и ресайзы уже не получится.
А если есть пара миллионов вертексов? Итог думаю вполне понятен.
Тебе, перед тем как спорить с взрослыми дядями про С++, пора узнать что у вектора есть метод std::vector::reserve( size_type new_cap ).


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 13:19
Как-то все начали наезжать на ресайзы вектора... А как вы стандартные массивы ресайзить собрались? О_о

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


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

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 30, 2014, 13:23

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

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 13:26
Отлично, и сколько будет О(n) при n=0 ?
О(n) не будет нисколько.
О(n) это значит что по верхней границе, линейная сложность.

Ну если для тебя добавление элемента в конец массива и присваивание элемента массива по индексу это аналогичные операции, то о чем мы тогда разговариваем ?
Начнем наш урок с начала. Вектор это не массив. Это контейнер.
Теперь ко второй претензии...
Аналогичные? Да.
Идентичные? Нет.

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

Тебе, перед тем как спорить с взрослыми дядями про С++, пора узнать что у вектора есть метод std::vector::reserve( size_type new_cap ).
Взрослый дядя, ты свой аргумент уже откомпилировал?)))
Ты может и чутка постарше, но дядя это ты явно преувеличил свои возможности!)))


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 30, 2014, 13:26
И вообще, лучше всегда предпочитать более высокий уровень (вектор), ибо работа с ним менее подвержена ошибкам и более понятна. А вот если нужно оптимизировать по скорости, тогда милости просим, делайте все на указателях, но изолируйте этот код и добавьте описание.
Всё правильно. Но выступают не против вектора конкретно, а против его бездумного использования везде и всюду :). Что вектора нужно использовать везде, а "старые" массивы выкинуть на свалку истории. Хотя эти штуки друг другу не мешают, и использовать надо то, что резонно и оптимально в конкретном случае.


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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 13:31
Какая сложность операций? На паре тысяч элементов ты не заметишь разницу по скорости между пушбэком на пустой вектор и первоначальным ресайзом. Если скорость становится более критичной, делаем ресайз изначально.

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

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

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

Об чем и речь ;)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 30, 2014, 13:33
1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. ;)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 13:50
1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. ;)

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


Название: Re: Современные одномерные и двумерные масс&#
Отправлено: ViTech от Октябрь 30, 2014, 13:52
Лично я не юзаю сишные массивы. Если изменять не надо и можно вычислить на этапе компиляции - std::array, в противном случае вектор.
std::array - разумная замена сишным массивам. Если компилятор поддерживает С++11. Но некоторым всё еще приходится возиться со старыми :).


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Igors от Октябрь 30, 2014, 13:56
...и использовать надо то, что резонно и оптимально в конкретном случае.
В данном случае согласен с научным работником. И немало ситуаций где вектор нехорош. Напр вот такое
Код
C++ (Qt)
   std::vector< std::vector<int> > arr( 5 );
 
Но дяди как-то на это не обратили внимания :) А по мне так глаз режет


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Пантер от Октябрь 30, 2014, 14:12
1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. ;)

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 30, 2014, 14:18
1. Если делаем ресайз изначально, про пуш бэк забудь.

Есть reserve еще. ;)

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

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: alex312 от Октябрь 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
Дополнения, конструктивная критика приветствуется.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 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;
...


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 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.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: alex312 от Октябрь 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 создаются на стеке, а вектор лезет в кучу.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 30, 2014, 19:17
А вот Vector self (inline) выполняется действительно намного дольше.
Что естественно. Потому как массив и array создаются на стеке, а вектор лезет в кучу.

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


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Igors от Октябрь 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/платформы


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 31, 2014, 10:54
Всего лишь declspec (вместо attribute) и инициализацию вектора вручную - и все работает.
Как говорится: "мелочь, а приятно" :). Руками данные пушбэкать совсем не интересно, а если загонять данные из статического массива, то смысла в этом векторе совсем уж не остаётся, в рассматриваемом контексте. То хоть были только тормоза, теперь ещё и неудобство инициализации добавилось :).


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: 8Observer8 от Октябрь 31, 2014, 11:27
Понаписали то. Дневной запас энергии у человека ограничен. Лучше бы эту энергию потратили на создание какого-нибудь полезного приложения, выручили кого-то, заработали денег или\и зарядку сделали (а то уж глаза наверное устали, на форумах столько сидеть) А негативные эмоции вообще разрушают, приводят к болезням

Надо спорить конструктивно. Если понял, что был не прав лучше обрадоваться, что наконец-то понял. Так и поступаю

C++, с точки зрения разработчика приложений, развивается по такому пути:

1) Писать как можно быстрее. Чем быстрее фирма отдаст проект заказчику (на рынок), тем больше она денег заработает

2) Обезопасить себя. Раньше программисту приходилось писать new и delete, потом придумали идиому RAII, теперь есть std::make_shared и std::make_unique. Теперь можно вообще не писать new и delete и освободить себя и от лишней головной боли, так как оператор delete опасен тем, что:

- можно забыть его написать
- можно написать его два раза
- можно попытаться использовать объект после delete

3) Для стандартных задач применять стандартные решения. Теперь можно комбинировать стандартные алгоритмы, контейнеры, лямбды, функторы, итераторы, регулярные выражения и т.д. решая 99% стандартных задач стандартным образом. Тем самым: уменьшаем время разработки, уменьшаем количество ошибок, программисты лучше понимают друг друга, когда видят перед собой стандартные решения

Нужно идти в ногу со временем

Чем быстрее заказчик получит своё приложение, тем быстрее фирма может перейти к выполнению следующего заказа, тем больше фирма заработает за определённое время (например, за год) Все становятся счастливее и довольнее

По поводу std::vector и статического (динамического) массива - ничего хоть сколько-нибудь убедительного не увидел. Не люблю пустословия. Давайте на конкретных примерах и конкретных задачах

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

Вот как я решил эту задачу с использованием стандартных средств C++11:

Код
C++ (Qt)
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <algorithm>
#include <iterator>
 
template <typename Type>
std::vector<Type> getArrya( std::size_t n );
 
template <typename Type>
void showArray( const std::vector<Type> &arr );
 
int main()
{
   // Get size
   std::cout << "Enter a size for the array: ";
   size_t n;
   std::cin >> n;
 
   // Get array
   std::vector<int> arr;
   arr = getArrya<int>( n );
 
   // Before
   std::cout << "Before: " << std::endl;
   showArray( arr );
 
   // Sort
   std::sort( arr.begin(), arr.end(), []( int i , int j ) { return i > j; } );
 
   // After
   std::cout << "After: " << std::endl;
   showArray( arr );
   std::cout << std::endl;
 
   return 0;
}
 
template <typename Type>
std::vector<Type> getArrya( std::size_t n )
{
   std::vector<int> arr( n );
   std::srand( std::time( NULL ) );
   std::transform( arr.begin(), arr.end(), arr.begin(),
                   []( Type i ) { return std::rand() % 100; } );
   return arr;
}
 
template <typename Type>
void showArray( const std::vector<Type> &arr )
{
   std::copy( arr.begin(), arr.end(),
              std::ostream_iterator<Type>( std::cout, " " ) );
   std::cout << std::endl;
}
 

Приведите аналог моего решения с использованием динамического массива, измерьте время и покажите насколько ваше решение быстрее моего. Только укажите характеристики своего компьютера. Сравним ещё по количеству строк кода и по сложным местам, где можно было совершить ошибку (то есть по сложности)

Либо приведите свою задачу решённую с помощью статического (динамического) массива. А я решу её с помощью std::vector. И возможно мы наглядно увидим, что использование статического (динамического) массива оказалось быстрее std::vector. Настолько быстрее, что заказчик смог это заметить

Приведите несколько ситуаций, где возможно только применение статического (динамического) массива и ни в коем случае нельзя применять std::vector

Я уверен, что в 99% случаев можно обойтись в своих приложениях std::vector (ну или другим контейнером). А использовать статические (динамические) массивы только в самых крайних случаях. Я бы хотел, чтобы каждый перечислил все известные ему случаи. Буду очень рад! Спасибо!


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: ViTech от Октябрь 31, 2014, 12:03
Понаписали то. Дневной запас энергии у человека ограничен. Лучше бы эту энергию потратили на создание какого-нибудь полезного приложения, выручили кого-то, заработали денег или\и зарядку сделали (а то уж глаза наверное устали, на форумах столько сидеть) А негативные эмоции вообще разрушают, приводят к болезням
Может тогда стоит почитать то, на что другие потратили своё время, такое дорогое.

По поводу std::vector и статического (динамического) массива - ничего хоть сколько-нибудь убедительного не увидел. Не люблю пустословия. Давайте на конкретных примерах и конкретных задачах.

Либо приведите свою задачу решённую с помощью статического (динамического) массива. А я решу её с помощью std::vector. И возможно мы наглядно увидим, что использование статического (динамического) массива оказалось быстрее std::vector. Настолько быстрее, что заказчик смог это заметить

Приведите несколько ситуаций, где возможно только применение статического (динамического) массива и ни в коем случае нельзя применять std::vector
В теме есть конкретный пример, где не стоит применять вектор. Разжевали, в рот положили, ещё и тестовый файл для сравнения скоростных характеристик выложили.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Октябрь 31, 2014, 12:05
Автор вообще неадекватен...


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Igors от Октябрь 31, 2014, 13:25
По поводу std::vector и статического (динамического) массива - ничего хоть сколько-нибудь убедительного не увидел.
Я уже дважды привел пример где бездумное использование вектора неудачно. Привожу в 3-й раз.
Код
C++ (Qt)
   std::vector< std::vector<int> > arr( 5 );
 
Кстати "отсталый" программист на С никогда бы не написал такого говнокода. Хотя возможно он и не слыхал ни о каком векторе  :)

Вы неоднократно употребляете термины "статический/динамический" массив. Возможно Вы имели ввиду объявление массива и массив выделяемый в куче с помощью new/malloc. Но это не соответствует терминам языка где static означает область видимости, а "динамический массив" просто отсутствует.

..потом придумали идиому RAII, теперь есть std::make_shared и std::make_unique.
:) Не надо парИть так высоко. Разберитесь (по-настоящему, глубоко) почему Ваш 2-мерный массив очень плох, толку будет больше.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: alex312 от Октябрь 31, 2014, 13:52
Не надо парИть так высоко. Разберитесь (по-настоящему, глубоко) почему Ваш 2-мерный массив очень плох, толку будет больше.
Не надо умничать. Обьясните "на пальцах" почему его двумерный массив плох и говнокод. Мне совсем не очевидно.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: Igors от Ноябрь 01, 2014, 08:49
Не надо умничать. Обьясните "на пальцах" почему его двумерный массив плох и говнокод. Мне совсем не очевидно.
Умничаю здесь не я. Основные соображения при выборе контейнера

- можно ли опираться на адрес элемента или придется хранить его индекс (больше забот)?
- чем грозит вставка/удаление?

В случае 2-мерного массива это прекрасно решается (в отличие от 1-мерного). И в Qt есть хорошее готовое решение. Поэтому странно что для Вас это неочевидно.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: _Bers от Ноябрь 01, 2014, 19:07
1. Стандартные средства являются кросс-платформенными, и не являются компиляторо-зависимыми.

2. Что касается межпроцессового взаимодействия: существует ограничение на использование rtti.
Поскольку, оно является unspecified behavior.

3. Не нужно путать "компиляторо-зависимость" и "зависимость от платформы".

Примером зависимости от платформы может служить, например "порядок следования байтов".
https://ru.wikipedia.org/wiki/%CF%EE%F0%FF%E4%EE%EA_%E1%E0%E9%F2%EE%E2

Очевидно, что одного лишь этого нюанса достаточно, что бы создать прецедент бинарной несовместимости.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Ноябрь 02, 2014, 23:09
1. Стандартные средства являются кросс-платформенными, и не являются компиляторо-зависимыми.

2. Что касается межпроцессового взаимодействия: существует ограничение на использование rtti.
Поскольку, оно является unspecified behavior.

3. Не нужно путать "компиляторо-зависимость" и "зависимость от платформы".

Примером зависимости от платформы может служить, например "порядок следования байтов".
https://ru.wikipedia.org/wiki/%CF%EE%F0%FF%E4%EE%EA_%E1%E0%E9%F2%EE%E2

Очевидно, что одного лишь этого нюанса достаточно, что бы создать прецедент бинарной несовместимости.


1. Стандартные средства являются кросс-платформенными, и не являются компиляторо-зависимыми.

то что описано в с++11 можно отнести к стандартным средствам?


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: _Bers от Ноябрь 02, 2014, 23:46
то что описано в с++11 можно отнести к стандартным средствам?

Вы хотите знать, является ли стандартным то, что описано в стандарте?




Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Ноябрь 03, 2014, 00:16
то что описано в с++11 можно отнести к стандартным средствам?

Вы хотите знать, является ли стандартным то, что описано в стандарте?

Хорошо, давай так. Есть msvs compiler, им никто не пользуется и он никому не нужен?


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: _Bers от Ноябрь 03, 2014, 14:23
Хорошо, давай так. Есть msvs compiler, им никто не пользуется и он никому не нужен?

Им пользуются. А значит - он нужен.

Однако, я не вижу связи между вашим первым и вторым вопросом.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: vulko от Ноябрь 05, 2014, 09:06
Хорошо, давай так. Есть msvs compiler, им никто не пользуется и он никому не нужен?

Им пользуются. А значит - он нужен.

Однако, я не вижу связи между вашим первым и вторым вопросом.

с++11 поддерживается только gcc.
тем не менее под виндой можно например запустить cygwin с gcc. а вот под линуксом врядли получится запустить msvs...

т.е. есть зависимость не только от платформы, но и от компилятора.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: kambala от Ноябрь 05, 2014, 14:02
с++11 поддерживается только gcc.
где ты это услышал? мс компилятор тоже поддерживает (возможно не полностью), как и клэнг.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: _Bers от Ноябрь 05, 2014, 20:17
с++11 поддерживается только gcc.
тем не менее под виндой можно например запустить cygwin с gcc. а вот под линуксом врядли получится запустить msvs...
т.е. есть зависимость не только от платформы, но и от компилятора.

Вы немножко ошибаетесь: помимо gcc в мейнстрим есть ещё такие топовые компиляторы, как:

Clang c++
http://clang.llvm.org/cxx_status.html

Visual C++ Compiler November 2013 CTP
http://www.microsoft.com/en-us/download/details.aspx?id=41151

Нельзя обойти вниманием порт gcc под виндовс в составе wingw.

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

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

Так например,
Visual C++ Compiler November 2013 CTP - бесплатен и ставиться отдельно с офф. сайта.
Он расширяет возможности базового компилятора CL, предоставляя улучшенную поддержку с++1y.

Но вы правы насчет зависимости от компиляторов: далеко не все они поддерживают стандарт языка на должном уровне.
Так например, базовая сборка CL для 2012 студии не умеет variardic template.

И учитывая новую политику комитета - до конца не будут поддерживать никогда.
Пока производители компиляторов осваивают текущие нововведения, уже будут выходить новые фичи.

Однако, если вернуться к нашим баранам: одно дело отсутствие поддержки некоторых частей стандарта.
И другое дело - поведение не по стандарту.

Даже если взять компилятор вижал студии CL  - он до сих пор не соответствует стандарту на все 100%.
Но даже на нем, код написанный согласно букве стандарта взлетает без проблем.

Все реализованное в стандартной библиотеке на 100% соответствует букве стандарта.


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: kuzulis от Ноябрь 05, 2014, 21:13
2 _Bers,

а "Visual C++ Compiler November 2013 CTP" - это что-то вроде SDK (как раньше были SDK 7x) ?
Или что это за зверь? Можно по-подробнее плз (в двух словах)?  :)


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: _Bers от Ноябрь 05, 2014, 21:32
2 _Bers,

а "Visual C++ Compiler November 2013 CTP" - это что-то вроде SDK (как раньше были SDK 7x) ?
Или что это за зверь? Можно по-подробнее плз (в двух словах)?  :)

Это - компилятор.

Я предоставил линк на официальный сайт майкрософт.
Там все написано.

Если в двух словах: идете по ссылке, качаете (установится автоматически).
После этого в настройках проекта сможете его выбрать для компиляции.
Вам станут доступны почти все плюшки c++1y




Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: kuzulis от Ноябрь 05, 2014, 21:51
Это понятно. Но вопрос мой такой: идут ли с этим пакетом кроме компилятора и сам рантайм, заголовки и прочее? Могу ли я использовать этот компилятор вообще без студии (в голой консольке)?


Название: Re: Современные одномерные и двумерные массивы на C++
Отправлено: kambala от Ноябрь 05, 2014, 22:20
This package requires VIsual Studio 2013 to be pre-installed on the machine.

а вин сдк все равно ставить придется.