12.1.4.1 : Un allocateur de données alignées

Nous pourions utiliser des bibliothèques tièrces ou des memalign et autre posix_memalign pour aligner nos données, mais nous pouvons jouer le jeu jusqu'au bout en changeant l'allocateur des std::vector pour qu'ils aient eux-même des données alignées noteOn rappel au passage qu'avoir des donneés alignées évite que compilateur d'ajouter un peal avant la boucle de calculs vectorisés.

1
2
#ifndef __ALIGNED_ALLOCATOR_H__
#define __ALIGNED_ALLOCATOR_H__


Les includes classiques pour allouer des trucs :
1
2
3
4
5
6
#include <new>
#include <limits>
#include <iostream>
#include <vector>

#include <malloc.h>


Notre allocateur :
1
2
3
4
5
6
7
8
9
10
11
///@brief Allocator wihch alignes data
template<typename T>
struct AlignedAllocator{
	///Value of the type of the current allocator (used by std::vector to avoid ambiguities if we use multiple template)
	typedef T value_type;
	AlignedAllocator () = default;	//Declare the current constructor as default constructor
	
	///Copy constructor from U type
	template<typename U>
	constexpr AlignedAllocator (const AlignedAllocator <U>&) noexcept {}
	


La fonction d'allocation noteQui n'est malheureusement que unidimensionnelle, donc pas de padding implicite :
1
2
3
4
5
6
7
8
9
10
	///Do the memory allocation
	/**	@param n : number of element to be allocated
	 * 	@return pointer to the allocated memory
	 * 	This function is nodiscard, so return value cannot be ignored
	 * 	We have to remove nodiscard when we make it static (and it works with std::vector)
	*/
	static /*[[nodiscard]]*/ T* allocate(std::size_t n){
		if(n > std::numeric_limits<std::size_t>::max() / sizeof(T)){
			throw std::bad_array_new_length();
		}


Ici, on utilise la macro VECTOR_ALIGNEMENT que l'on a définit dans le CMakeLists.txt, ce qui est moche, mais ce n'est qu'un exemple :
1
2
3
4
		T* p = static_cast<T*>(std::aligned_alloc(VECTOR_ALIGNEMENT, n * sizeof(T)));
		if(p != NULL){
			return p;
		}


Si l'allocation se passe mal, on râle :
1
2
		throw std::bad_alloc();
	}


La fonction de déallocation appelle juste std::free :
1
2
3
4
5
6
7
	///Free the allocated memory
	/**	@param p : pointer to be freed
	 * 	@param n : number of element allocated in p
	*/
	static void deallocate(T* p, std::size_t n) noexcept{
		std::free(p);
	}


On termine la déclaration et le fichier :
1
2
3
4
};


#endif


Le fichier AlignedAllocator.h complet :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/***************************************
	Auteur : Pierre Aubert
	Mail : pierre.aubert@lapp.in2p3.fr
	Licence : CeCILL-C
****************************************/

#ifndef __ALIGNED_ALLOCATOR_H__
#define __ALIGNED_ALLOCATOR_H__

#include <new>
#include <limits>
#include <iostream>
#include <vector>

#include <malloc.h>

///@brief Allocator wihch alignes data
template<typename T>
struct AlignedAllocator{
	///Value of the type of the current allocator (used by std::vector to avoid ambiguities if we use multiple template)
	typedef T value_type;
	AlignedAllocator () = default;	//Declare the current constructor as default constructor
	
	///Copy constructor from U type
	template<typename U>
	constexpr AlignedAllocator (const AlignedAllocator <U>&) noexcept {}
	
	///Do the memory allocation
	/**	@param n : number of element to be allocated
	 * 	@return pointer to the allocated memory
	 * 	This function is nodiscard, so return value cannot be ignored
	 * 	We have to remove nodiscard when we make it static (and it works with std::vector)
	*/
	static /*[[nodiscard]]*/ T* allocate(std::size_t n){
		if(n > std::numeric_limits<std::size_t>::max() / sizeof(T)){
			throw std::bad_array_new_length();
		}
		T* p = static_cast<T*>(std::aligned_alloc(VECTOR_ALIGNEMENT, n * sizeof(T)));
		if(p != NULL){
			return p;
		}
		throw std::bad_alloc();
	}
	///Free the allocated memory
	/**	@param p : pointer to be freed
	 * 	@param n : number of element allocated in p
	*/
	static void deallocate(T* p, std::size_t n) noexcept{
		std::free(p);
	}
};


#endif
Le fichier AlignedAllocator.h est disponible ici.