Я обнаружил, что оба компилятора MSVC и GCC выделяют по крайней мере один байт на каждый экземпляр класса, даже если класс является предикатом без переменных-члена (или с только статическими переменными-членами). Следующий код иллюстрирует точку.
#include <iostream>
class A
{
public:
bool operator()(int x) const
{
return x>0;
}
};
class B
{
public:
static int v;
static bool check(int x)
{
return x>0;
}
};
int B::v = 0;
void test()
{
A a;
B b;
std::cout << "sizeof(A)=" << sizeof(A) << "\n"
<< "sizeof(a)=" << sizeof(a) << "\n"
<< "sizeof(B)=" << sizeof(B) << "\n"
<< "sizeof(b)=" << sizeof(b) << "\n";
}
int main()
{
test();
return 0;
}
Вывод:
sizeof(A)=1
sizeof(a)=1
sizeof(B)=1
sizeof(b)=1
Мой вопрос: зачем компилятору это нужно? Единственная причина, по которой я могу придумать, - обеспечить, чтобы все указатели var-членов различались, поэтому мы можем различать два элемента типа A или B, сравнивая указатели с ними. Но стоимость этого довольно серьезная при работе с малогабаритными контейнерами. Учитывая возможное выравнивание данных, мы можем получить до 16 байтов на класс без vars (?!). Предположим, у нас есть пользовательский контейнер, который обычно содержит несколько значений int. Затем рассмотрим массив таких контейнеров (около 1000000 членов). Накладные расходы будут составлять 16 * 1000000! Типичным случаем, когда это может произойти, является контейнерный класс с предикатом сравнения, хранящимся в переменной-члене. Кроме того, учитывая, что экземпляр класса должен всегда занимать некоторое пространство, какой тип накладных расходов следует ожидать при вызове A() (значение)?