Безопасный sizeof для массивов в С++
Иногда приходится иметь дело с обычными массивами и указателями на них в С++. Также иногда встает задача определения количества элементов массиве на стадии компиляции.
Например, это можно слелать так:
#define arraysize(array) (sizeof(array) / sizeof(array[0]))
Но тут есть одна проблема. Если случайно передать в этот макрос не массив, а просто указатель, что ошибки компиляции не будет, но значение будет далеко от задуманного.
Вчера прочитал на Харбе (кстати, отличная статья), что в С++ можно сделать этот макрос более безопасным.
Вот код, который используется в Chrome:
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
Выглядит немного запутанно, но можно разобраться:
T (&array)[N]- определение массива (T array[N]), который передается по ссылкеchar (&ArraySizeHelper(...)[N]- функция, возвращающая массив по ссылкеsizeof(ArraySizeHelper(array))- определение размера возвращаемого функцией значения- Все это шаблон функции, параметризированный типом массива и его размером, который автоматически определяется компилятором при раскрытии шаблона. Так как функция реально не вызывается, то и тело ее определять не нужно.
Если честно, додуматься до такого непросто. Но макрос весьма хорош. Я взял себе на вооружение.
Кстати, можно поиграться с sizeof() от типа возвращаемого функцией значения:
#include <iostream>
#include <string>
std::string f() {
return std::string();
}
int main() {
std::cout << sizeof( (&f)() ) << std::endl;
std::cout << sizeof( std::string ) << std::endl;
return 0;
}
У меня на VS2010 выводит два раза число “28”.
Интересно, что в чистом С такой номер тоже проходит:
#include <stdio.h>
struct t {
char x[1024];
};
struct t f() {
struct t a;
return a;
}
int main() {
printf("%d\n", sizeof(struct t));
printf("%d\n", sizeof( (*f)() ));
return 0;
}
Печатает два раза “1024”.
Оригинальный пост | Disclaimer