Какая разница между OOP & Procedural подходами в рамках кэш память(процес использования памяти, загрузка...)?
В очень большом числе случаев, вызов метода затрагивает не все члены-данные объекта, а только их небольшую часть. (Это не всегда так, но в подавляющем большинстве практически встречающихся задач.) Шина память-процессор устроена так, что при обращении к отдельному байту, в кеш попадет некоторая область памяти, содержащая этот байт. Т.е. по шине будут переданы в т.ч. данные которые нам не понадобятся.
Рассмотрим сценарий:
struct ABC {
int a,b,c,d;
void inc() { ++a; }
};
ABC abc_vetcor[1024];
....
for( ABC& a : abc_vetcor )
a.inc();
В через шину память будет перекачено sizeof(int)*4*1024
байт, хотя для выполнения поставленной задачи достаточной было четверти этих данных.
Чтобы оптимизировать передачу данных через шину нужно изменить упорядочение данных в памяти, так чтобы члены данных a
принадлежащие разным объектам лежали рядом. Например:
struct ABC {
int a,b,c,d;
void inc() { ++a; }
};
template<size_t size>
struct ABC_vector {
int a[size];
int b[size];
int c[size];
int d[size];
void inc_all() {
for(int& a_i : a ) ++a_i;
}
};
Однако, здесь мы вынуждены были скопировать и "раскрыть" метод inc()
. Но это противоречит инкапсуляции, которая является краеугольным камнем ООП(!).
В принципе, для C++ существуют технические приемы и библиотеки, которые позволяют реорганизовывать массивы объектов в памяти, оставаясь в рамках ООП. (CRTP подход + использование метаданных.) Но это сильно усложняет код, и не решает проблему других часто встречающихся сценариев. Например обход коллекций разнородных объектов.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Как настроить visual studio, чтобы консоль не закрываласьПроблема в том, что использую классы, где деструктор выводит какое-то сообщение
В задаче нужно посчитать число фибоначчи наоборот (не со сложением, а с вычитанием)