STL에 기본 할당자 대신 자신이 만든 것 이용하기
Effective STL ch.10, 11
예)
// SharedMemory Allocator
#include <map>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
#include "mm.h"
void *mallocShared(size_t bytes)
{
return MM_malloc(bytes);
}
void freeShared(void *p)
{
MM_free(p);
}
template<typename T>
class SharedMemoryAllocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T * const_pointer;
typedef T& reference;
typedef const T * const_reference;
typedef T value_type;
template<typename U>
struct rebind
{
typedef SharedMemoryAllocator<U> other;
};
SharedMemoryAllocator() throw() { }
SharedMemoryAllocator(const SharedMemoryAllocator&) throw() { }
template<typename U>
SharedMemoryAllocator(const SharedMemoryAllocator<U>&) throw() { }
~SharedMemoryAllocator() throw() { }
pointer address(reference __x) const { return &__x; }
const_pointer address(const_reference __x) const { return &__x; }
pointer allocate(size_type numObjects, const void *localityHint = 0)
{
return static_cast<pointer>(mallocShared(numObjects * sizeof(T)));
}
void deallocate(pointer ptrToMemory, size_type numObjects)
{
freeShared(ptrToMemory);
}
size_type max_size() const throw()
{
return size_t(-1) / sizeof(T);
}
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 402. wrong new expression in [some_] allocator::construct
void construct(pointer __p, const T& __val)
{
new(__p) T(__val); // placement new
}
void destroy(pointer __p)
{
__p->~T();
}
};
template<typename T>
inline bool operator==(const SharedMemoryAllocator<T>&, const SharedMemoryAllocator<T>&)
{
return true; // 왜 항상 true일까?
}
template<typename T>
inline bool operator!=(const SharedMemoryAllocator<T>&, const SharedMemoryAllocator<T>&)
{
return false; // 왜 항상 false일까?
}
//! createOnShared로 만든 type은 꼭 destructor를 명시적으로 불러주어야 한다.
template<typename T>
T *createOnShared()
{
void *chunk_p = mallocShared(sizeof(T)); // memory chunk
if (chunk_p == NULL)
return NULL;
T *shm_p = new(chunk_p) T; // placement new(new가 실제로 메모리를 잡지는 않은)
return shm_p;
}
template<typename T>
void releaseOnShared(T *shm_p)
{
shm_p->~T();
void *chunk_p = reinterpret_cast<void*>(shm_p);
freeShared(chunk_p);
}
이용)
typedef std::vector<int, SharedMemoryAllocator<int> > SharedIntVector;
MM_create(100000000, "testtest");
SharedIntVector *plv = createOnShared<SharedIntVector>();
plv->push_back(1);
printf("MM_available : %d\n", MM_available());
releaseOnShared<SharedIntVector>(plv);
이용2)
// 참고
// /usr/include/c++/3.2.2/string
// /usr/include/c++/3.2.2/bits/stringfwd.h
typedef std::basic_string<char, std::char_traits<char>, SharedMemoryAllocator<char> > SharedStr;
typedef std::vector<SharedStr, SharedMemoryAllocator<SharedStr> > SharedStrVec;
// /usr/include/c++/3.2.2/map
// /usr/include/c++/3.2.2/bits/stl_map.h
typedef std::map<SharedStr, SharedStr, less<SharedStr>, SharedMemoryAllocator<SharedStr> > SharedStrMap;
void *pChunk1;
pChunk1 = shAlloc1.malloc(sizeof(SharedStrVec));
SharedStrVec *shVecStr1 = new(pChunk1) SharedStrVec;
void *pChunk2;
pChunk2 = shAlloc1.malloc(sizeof(SharedStrMap));
SharedStrMap *map = new(pChunk2) SharedStrMap;
shVecStr1->push_back("1");
shVecStr1->push_back("2");
shVecStr1->push_back("3");
map->insert(SharedStrMap::value_type("1", "1"));
map->insert(SharedStrMap::value_type("2", "2"));
map->insert(SharedStrMap::value_type("3", "3"));
pid_t p = fork();
if (p == 0) {
// child
printf("child start\n");
shVecStr1->push_back("4");
shVecStr1->push_back("5");
shVecStr1->push_back("6");
map->insert(SharedStrMap::value_type("4", "4"));
map->insert(SharedStrMap::value_type("5", "5"));
map->insert(SharedStrMap::value_type("6", "6"));
printf("child end\n");
exit(0);
} else if (p > 0) {
// parent
sleep(3);
waitpid(p, NULL, 0);
printf("parent start\n");
shVecStr1->push_back("7");
shVecStr1->push_back("8");
shVecStr1->push_back("9");
map->insert(SharedStrMap::value_type("7", "7"));
map->insert(SharedStrMap::value_type("8", "8"));
map->insert(SharedStrMap::value_type("9", "9"));
SharedStrVec::iterator it;
for (it = shVecStr1->begin(); it != shVecStr1->end(); it++) {
printf("%s\n", it->c_str());
}
SharedStrMap::iterator it2;
for (it2 = map->begin(); it2 != map->end(); it2++) {
printf("%s -> %s \n", it2->first.c_str(), it2->second.c_str());
}
printf("parent end\n");
} else {
// error
fprintf(stderr, "fork() failed.\n");
}
shVecStr1->~SharedStrVec();
shAlloc1.free(pChunk1);
map->~SharedStrMap();
shAlloc1.free(pChunk2);
return 0;
}
placement new
이미 메모리가 할당되어 있을 때,
그 메모리에 object를 넣고 생성자를 불러줌.
(일반적인 new와는 달리 메모리를 할당하는 일은 하지 않는 다.)
소멸자도 수동으로 불러줘야 하고
메모리 해제도 raw memory에 대해서 해줘야 한다.
참고)
More Effective C++, Item 4, 8
Linux에서 gcc 3.4를 설치한 후 /usr/include/c++/3.4/ext/new_allocator.h
댓글 없음:
댓글 쓰기