Фухъ, добрался. 3587ms elapsed. shared_point работает, не игнорируется. Кривыми руками кое-как прикрутил кастомный аллокатор. Зачем там создаётся instance аллокатора, при том, что все переменные аллокатора static, уже забыл, но надо было правильно имплементировать не stateless аллокатор, а с нестатическими переменными классами почему-то творится дикая дичь. Хочу повторить, что постановка задачи изначально абсурдная, но интересовали детали имплементации. С момента последних ковыряний в аллокаторе утекло много воды, в тот раз как-то легче для вектора получилось. Сейчас за такой код меня на код-ревью расстреляет взвод по утру. Но тут же дружественно настроенные коллеги, а не работа.
Code: Select all
#include <memory>
#include <chrono>
#include <ctime>
#include <iostream>
static void* s_pool = nullptr;
static int s_nItems = 0;
static int s_nAllocated = 0;
static int s_nLastFreed = -1;
template <typename T>
class myallocator: public std::allocator<T>
{
public:
// typedefs
typedef T value_type;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
pointer address(reference r) { return &r; }
const_pointer address(const_reference r) { return &r; }
template< class U >
struct rebind { typedef myallocator< U > other; };
template< class U >
myallocator( const myallocator< U >& other ) throw()
: m_pool( reinterpret_cast<T*&>(s_pool) ) {}
explicit myallocator(int nItems) throw() : m_pool( reinterpret_cast<T*&>(s_pool) )
{
if (s_pool == nullptr)
{
s_nItems = nItems;
s_pool = new T[s_nItems];
}
}
myallocator() throw(): m_pool( s_pool ) { }
explicit myallocator(const myallocator &a) throw(): m_pool( reinterpret_cast<T*&>(s_pool) ) { }
// ~myallocator() throw() { delete[] s_pool; }
bool operator==(myallocator const&) { return true; }
bool operator!=(myallocator const& a) { return !operator==(a); }
T& operator[](int idx) { return m_pool[idx]; }
pointer allocate(size_type n, const void *hint=0)
{
pointer p = nullptr;
if (s_nLastFreed != -1)
p = &m_pool[ s_nLastFreed ];
else if (s_nAllocated < s_nItems)
p = &m_pool[ s_nAllocated ++ ];
return p;
}
void deallocate(pointer p, size_type n)
{
s_nLastFreed = n;
return; // std::allocator<T>::deallocate(p, n);
}
size_type max_size() const {
return static_cast<size_type>(-1) / sizeof(value_type);
}
void construct(pointer p, const T& t) { new(p) T(t); }
void destroy(pointer p) { p->~T(); }
private:
T*& m_pool;
/// disallow assignment
void operator=( const myallocator& );
};
struct Data
{
int payload;
Data() : payload(0) {
}
Data(int value) : payload(value) {
}
};
typedef std::shared_ptr<const Data> data_ptr;
typedef data_ptr* data_pptr;
const int COUNT = 100;
int main(int argc, const char* argv[])
{
auto start = std::chrono::system_clock::now();
myallocator<data_ptr> MyAllocator( COUNT );
data_pptr data[COUNT];
for (int i = 0; i < COUNT; i++) {
data[i] = reinterpret_cast<data_pptr>( &std::allocate_shared<Data, myallocator<data_ptr>>( MyAllocator, i ) );
}
data_ptr* current = data[0];
for(long iter = 0; iter < 100000000; iter ++) {
int nextIndex = ((*current)->payload + 1) % COUNT;
data_ptr* newNode = data[nextIndex];
// Yes, here we have shared_ptr working *data[nextIndex] is shared_ptr by val
*data[nextIndex] = std::allocate_shared<Data, myallocator<data_ptr>>(MyAllocator, ((*current)->payload + (*newNode)->payload + 1) % COUNT);
current = newNode;
}
auto finish = std::chrono::system_clock::now();
int64_t elapsed_seconds = std::chrono::duration_cast<std::chrono::milliseconds>( finish - start ).count();
std::cout << "\n" << elapsed_seconds << "ms elapsed";
return 0;
}
... and even then it's rare that you'll be going there...