Petroglif

Общие функции

В этой главе обсуждаются общеупотребимые функции и методы, а именно:

  • Распределение памяти
  • Манипуляции с участками памяти (инициализация, копирование, перемещение)
  • Ввод-вывод
  • Манипуляции со строковыми переменными и константами
  • Математические функции
  • Распределение памяти

    Функции malloc, calloc, realloc, free, определенные в стандартной библиотеке не используются в проекте на прямую. Вместо них применяются статические функции класса SAlloc. Ниже приведено упрощенное определение этого класса.

    
    	class SAlloc {
    	public:
    		//
    		// Descr: Функция, замещающая malloc.
    		//
    		static void * FASTCALL M(size_t sz);
    		//
    		// Descr: Функция, замещающая calloc.
    		//
    		static void * FASTCALL C(size_t n, size_t sz);
    		//
    		// Descr: Функция, замещающая realloc.
    		//
    		static void * FASTCALL R(void * ptr, size_t sz);
    		//
    		// Descr: Функция, замещающая free.
    		//
    		static void   FASTCALL F(void * ptr);
    	};
    

    Существуют две причины, по которым реализовано такое замещение:

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

    Манипуляции с участками памяти

    Функции memcpy, memmove, memset, memcmp опеределены в slib.h как макросы, для использования реализации из библиотеки Agner Fog (www.agner.org).Для инициализации памяти нулевыми байтами вместо общеупотребимого memset(ptr, 0, size) используется собственная функция memzero(ptr, size). Мотивацией для этого является удаление лишнего параметра в огромном числе вызовов, что в купе с соглашением вызова FASTCALL дает заметное снижение размера кода. Кроме того, функция memzero отдельно обрабатывает некоторые размеры инициализируемых участков памяти для ускорения.

    Для обнуления участков памяти, размер которых может быть вычислен на этапе компиляции оператором sizeof используется макрос MEMSZERO(). Пример:

    
    	void foo(void * ptr, size_t size)
    	{
    		char local_buf[256];
    		MEMSZERO(local_buf); // Правильно: sizeof(local_buf) возвращает адекватный результат
    		// MEMSZERO(ptr); // ! Ни в коем случае - будут обнулены 
    			// только первые 4 байта (8 на x64)
    		memzero(ptr, size); // Правильно
    	}
    
    Еще один макрос THISZERO() используется для полного обнуления экземпляра структуры или класса. Часто используется в конструкторах. Осторожно: этот макрос ни в коем случае не следует использовать для классов, имеющих виртуальные функции - он обнулит указатель на таблицу виртуальных функций в результате чего программа обязательно аварийно завершится при попытке обращения к любой из виртуальных функций класса.

    
    	class SomeClass {
    	public:
    		SomeClass()
    		{
    			THISZERO(); // Здесь можно использовать. 
    				// Класс не определяет ни одной виртуальной функции.
    		}
    		int    A;
    		int    B;
    	};
    	
    	class SomeClassWithVirtualFunctions {
    	public:
    		SomeClass()
    		{
    			THISZERO(); // ! Ни за что не делайте так - виртуальный 
    				// деструктор или иные виртуальные функции заставляют 
    				// компилятор вставить первым членом в экземпляре класса
    				// указатель на таблицу виртуальных функций. 
    				// В результате обнуления этот указатель станет нулевым.
    		}
    		virtual  SomeClass()
    		{
    		}
    		int    A;
    		int    B;
    	};	
    

    OOO "Петроглиф"
    Copyright © 2019