J'écris un allocateur avec une référence à une autre instance d'une classe qui suit le nombre d'octets alloués. Ci-dessous est un exemple minimal de ce que j'essaie de faire (adapté de here), sans la classe de suivi de mémoire entière, à la place j'ai fait référence à un int qui recueille les octets qui ont été alloués jusqu'à présent. Cette référence est attribué, à l'intérieur principal et devrait être transmis au CustomAllocator:Comment puis-je transmettre exactement le même état d'un allocateur personnalisé à plusieurs conteneurs?
#include <limits> // numeric_limits
#include <iostream>
#include <typeinfo> // typeid
// container
#include <vector>
#include <list>
#include <forward_list>
template<typename T>
class CustomAllocator {
public:
// type definitions
typedef T value_type; /** Element type */
typedef T* pointer; /** Pointer to element */
typedef T& reference; /** Reference to element */
typedef const T* const_pointer; /** Pointer to constant element */
typedef const T& const_reference; /** Reference to constant element */
typedef std::size_t size_type; /** Quantities of elements */
typedef std::ptrdiff_t difference_type; /** Difference between two pointers */
template<typename U>
struct rebind {
typedef CustomAllocator<U> other;
};
// return maximum number of elements that can be allocated
size_type max_size() const throw() {
return std::numeric_limits<std::size_t>::max()/sizeof(T);
}
CustomAllocator(std::size_t& memAllocated) :
m_totalMemAllocated(memAllocated) {
std::cout << "construct " << typeid(T).name() << std::endl;
}
CustomAllocator(const CustomAllocator& src) :
m_totalMemAllocated(src.m_totalMemAllocated) {
std::cout << "copy construct " << typeid(T).name() << std::endl;
}
template<class U>
CustomAllocator(const CustomAllocator<U>& src) :
m_totalMemAllocated(src.getTotalMemAllocated()) {
}
// allocate but don't initialize num elements of type T
pointer allocate(size_type num, const void* = 0) {
m_totalMemAllocated += num * sizeof(T);
// print message and allocate memory with global new
std::cout << "allocate " << num << " element(s)" << " of size "
<< sizeof(T) << std::endl;
pointer ret = (pointer) (::operator new(num * sizeof(T)));
std::cout << " allocated at: " << (void*) ret << std::endl;
return ret;
}
// deallocate storage p of deleted elements
void deallocate(pointer p, size_type num) {
m_totalMemAllocated -= num * sizeof(T);
// print message and deallocate memory with global delete
std::cout << "deallocate " << num << " element(s)" << " of size "
<< sizeof(T) << " at: " << (void*) p << std::endl;
::operator delete((void*) p);
}
// initialize elements of allocated storage p with value value
// no need to call rebind with this variadic template anymore in C++11
template<typename _U, typename ... _Args>
void construct(_U* p, _Args&&... args) {
::new ((void *) p) _U(std::forward<_Args>(args)...);
}
// destroy elements of initialized storage p
template<typename _U>
void destroy(_U* p) {
p->~_U();
}
// return address of values
pointer address (reference value) const {
return &value;
}
const_pointer address (const_reference value) const {
return &value;
}
private:
std::size_t& m_totalMemAllocated;
};
template<typename T, typename U>
bool operator==(const CustomAllocator<T> a, const CustomAllocator<U>& b) {
return true;
}
template<typename T, typename U>
bool operator!=(const CustomAllocator<T>& a, const CustomAllocator<U>& b) {
return false;
}
int main() {
std::size_t memAllocated = 0;
CustomAllocator<int> allocatorInstance(memAllocated);
std::vector<int> foo(allocatorInstance);
foo.push_back(23);
foo.push_back(12);
foo.push_back(8);
std::cout << "---" << std::endl;
// here the same
std::list<double> bar(allocatorInstance);
bar.push_back(3.44);
bar.push_back(1.18);
bar.push_back(2.25);
std::cout << "---" << std::endl;
// debug output
for (auto x : foo)
std::cout << x << " ";
for (auto x : bar)
std::cout << x << " ";
std::cout << "\nalloc_count: " << memAllocated << std::endl;
std::cout << '\n';
return 0;
}
Mon problème est que je ne sais pas comment passer le même état exact (dans l'exemple m_totalMemAllocated) d'une instance de allocateur à la deux autres conteneurs (ici: foo et bar). Depuis la norme dit que les allocateurs C++ 11 peuvent avoir un état.
Mise à jour:
Merci pour les réponses à ce jour :)
Je sais que vous passez habituellement CustomAllocators comme argument de modèle pour les conteneurs std; comme ceci:
std::vector<int, CustomAllocator<int> > foo;
std::list<double, CustomAllocator<double> > bar;
mais ici j'ai un état que je ne suis pas en mesure de transmettre et le constructeur par défaut recevrais appelé que je ne peux pas utiliser à moins que je donner à la référence une valeur par défaut (mais ce n'est pas ce que je veux non plus).
Mettre le
std::size_t memAllocated = 0;
du principal dans l'environnement global signifierait que tous les conteneurs qui utilisent le CustomAllocator finiraient à l'aide du memAllocated défini au niveau mondial. Mais je veux l'étendre afin que je puisse avoir de la mémoire additionnelle ou une instance memAllocated2 qui est ensuite assignée à d'autres instances d'allocateurs.
Side-Note:
Pour une version stateful de allocateurs pour différents conteneurs que STD-conteneurs, voir
How to track memory usage using EASTL?
Une méthode simple consisterait à rendre chaque instance d'allocateur «sans état» et à faire en sorte que le type lui-même conserve un état global entre les instances. – KABoissonneault
Errr ... vous ne voulez probablement pas dire 'vector', mais 'vector >'? –
À l'aide de ce modèle d'allocateur, les instances d'allocateur doivent être sans état. Cependant, en C++ 17, nous pouvons utiliser des versions des conteneurs dans l'espace de noms 'std :: pmr', qui supportent [*** p ** olymorphic ** m ** emory ** r ** sources *] (http : //fr.cppreference.com/w/cpp/memory/polymorphic_allocator). – BoBTFish