Да, вы правы, как по скорости, так и по памяти.
Указатели почти всегда занимают больше байтов, чем ваши стандартные int
и, особенно, bool
и char
типы данных. На современных машинах указатели обычно имеют размер 8 байт, тогда как char
почти всегда занимает всего 1 байт.
В этом примере для доступа к char
и bool
из Foo
требуется больше машинных инструкций, чем для доступа из Bar
:
struct Foo
{
char * c; // single character
bool * b; // single bool
};
struct Bar
{
char c;
bool b;
};
... И если мы решим сделать какие-то массивы, то размер массивов Foo
будет в 8 раз больше - и код более разбросан, так что это означает, что у вас будет намного больше промахов кеша.
#include <vector>
int main()
{
int size = 1000000;
std::vector<Foo> foo(size);
std::vector<Bar> bar(size);
return 0;
}
Как указал dmckee, одна копия однобайтового bool
и одна копия указателя работают так же быстро:
bool num1, num2,* p1, * p2;
num1 = num2; // this takes one clock cycle
p1 = p2; // this takes another
Как сказал dmckee, это верно, когда вы используете 64-битную архитектуру.
Однако копирование массивов int
s, bool
s и char
s может быть намного быстрее, потому что мы можем втиснуть их кратно в каждый регистр:
#include <iostream>
int main ()
{
const int n_elements = 100000 * sizeof(int64_t);
bool A[n_elements];
bool B[n_elements];
int64_t * A_fast = (int64_t *) A;
int64_t * B_fast = (int64_t *) B;
const int n_quick_elements = n_elements / sizeof(int64_t);
for (int i = 0; i < 10000; ++i)
for (int j = 0; j < n_quick_elements; ++j)
A_fast[j] = B_fast[j];
return 0;
}
Контейнеры STL и другие хорошие библиотеки делают это за нас, используя type_traits
(is_trivially_copyable
) и std::memcopy
. Использование указателей под ложным предлогом того, что они всегда такие же быстрые, может помешать оптимизации этих библиотек.
Вывод: на этих примерах это может показаться очевидным, но используйте указатели/ссылки на базовые типы данных только тогда, когда вам нужно получить/дать доступ к исходному объекту.
person
Elliott
schedule
13.12.2019