stl error: wrong allocator coversions?

Have in code:
1
2
3
  std::vector<foo, TBufferedAllocator<foo> > v_foo;
  //
  v_foo.get_allocator().BufReserve(100);


In particular my allocator have states, so everything done under c++11.
And i see that only way to get instantiated object is to call get_allocator() after continer was instantiated.
But instead of that stl tries to call copy constructor to allocator:

In file included from /usr/include/c++/4.7/vector:65:0,
from test_set.cpp:4:
/usr/include/c++/4.7/bits/stl_vector.h: In instantiation of ‘std::_Vector_base<_Tp, _Alloc>::allocator_type std::_Vector_base<_Tp, _Alloc>::get_allocator() const [with _Tp = foo; _Alloc = TBufferedAllocator<foo>; std::_Vector_base<_Tp, _Alloc>::allocator_type = TBufferedAllocator<foo>]’:
test_set.cpp:156:23: required from here
/usr/include/c++/4.7/bits/stl_vector.h:123:52: error: no matching function for call to ‘TBufferedAllocator<foo>::TBufferedAllocator(const _Tp_alloc_type&)’
/usr/include/c++/4.7/bits/stl_vector.h:123:52: note: candidates are:
test_set.cpp:19:5: note: TBufferedAllocator<T>::TBufferedAllocator() [with T = foo]
test_set.cpp:19:5: note: candidate expects 0 arguments, 1 provided
test_set.cpp:10:9: note: TBufferedAllocator<foo>::TBufferedAllocator(const TBufferedAllocator<foo>&)
test_set.cpp:10:9: note: no known conversion for argument 1 from ‘const _Tp_alloc_type {aka const std::allocator<foo>}’ to ‘const TBufferedAllocator<foo>&’
test_set.cpp: In instantiation of ‘void TBufferedAllocator<T>::BufReserve(int) [with T = foo]’:
test_set.cpp:156:39: required from here
test_set.cpp:47:14: error: return-statement with a value, in function returning 'void' [-fpermissive]
In file included from /usr/include/c++/4.7/set:61:0,
from test_set.cpp:3:


Moreover it tries to copy std::allocator instead of my class. Whats wrong?
That's not the intended usage.

You're supposed to call BufReserve() or otherwise prepare your allocator first, and then construct your vector.

1
2
3
TBufferedAllocator<foo> a;
a.BufReserve(100); // or even TBufferedAllocator<foo> a(100);
std::vector<foo,  TBufferedAllocator<foo>> v_foo(a);


Consider the implementations that always allocate some initial capacity() on construction!

get_allocator()'s purpose is to return a copy of the allocator (which is why it calls the copy constructor). What you do to that copy has no influence on the allocator the vector is using.

As for where std::allocator pops up, did you remember to implement rebind?

Consider the implementations that always allocate some initial capacity() on construction!

Yes, i know that in case of vector simply capacity() could solve my problem. But i need for set container actually.

And yeah.. It's time when i begin to understand real weaknesses of STL.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html

All i really did want to do is to create std::set with as fast as possible clear() functionality. And fast fill. It's a temp object that refills and clears during execution many times + fast search within it.
Are you referring to the return type of get_allocator()? What allocation strategy do you have in mind for your std::set that would make use of that?
I don't see anything useful in that c++11 standart! How properly to create allocator-with-states?
As i see now states rather should be static members of object because of stupid copying.
My allocation strategy is next - REALLY smart std::set object i.e. both nodes and data memory should be possible to pre-allocate as continuity memory areas
And clear() method with O(1) complexity for object reusage should be also implemented.
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// set::insert
#include <iostream>
#include <set>
#include <vector>
#include <memory>
#include <functional>

//using namespace std;
  template <class T> 
  class TBufferedAllocator: public std::allocator<T>
  {
  public:
    typedef T* pointer;
    typedef size_t size_type;
  private:
    static void * buf, *last, *curr;
    static size_t mem_cnt;
  public:
    TBufferedAllocator(): std::allocator<T>()
    {
      buf=NULL;
      mem_cnt=0;
    }
    
    ~TBufferedAllocator()
    {
      FreeBuf();
    }
    
    void FreeBuf()
    {
      if (buf)
      {
        std::allocator<T>::deallocate((pointer)buf, mem_cnt);
        buf=NULL;
      }
    }
    
    void BufReserve(int count)
    {
      if (mem_cnt<count)
      {
        FreeBuf();
        mem_cnt=count;
        buf = std::allocator<T>::allocate(mem_cnt);
        last=((pointer)buf+mem_cnt);
      }
    }
    
    void Clear()
    {
      curr=buf;
    }
    
    pointer allocate(size_type n, const void * hint=0)
    {
      pointer res=(pointer)curr;
      //
      std::cout << "TBufferedAllocator::allocate called, size="<<n <<std::endl;
      curr=res+n;
      if (curr>last)
        throw("Space supposed to be pre-allocated!");
      return res;
    }
    
    void deallocate(pointer p, size_type n)
    {
      std::cout << "TBufferedAllocator::deallocate called, size="<<n <<std::endl;
      // no implementation, shouldn't actually be. Memory REALLY deallocates only in destructor or via mem change
    }
    
    template<class _Other>
    struct rebind
    {
      typedef TBufferedAllocator<_Other> other; 
    };
  };

  typedef struct _TMovedMols
  {
  private:
    union
    {
      uint32_t dummy;
      struct
      {
        unsigned int UniqueMolID:31;
        unsigned int Direction:1;
      };
    };
  public:
    _TMovedMols(int AUniqueMolID=0, int ADirection=0)
    {
      UniqueMolID=AUniqueMolID;
      Direction=ADirection;
    }
    
    _TMovedMols(const _TMovedMols &other)
    {
      dummy=other.dummy;
    }
    
    inline _TMovedMols & operator = (const _TMovedMols &other)
    {
      dummy=other.dummy;
      return *this;
    }
    
    inline bool operator < (const _TMovedMols &other) const
    {
      return UniqueMolID < other.UniqueMolID;
    }
  } TMovedMols;
  
  template <class T> 
  class TLocalSetAllocator : public TBufferedAllocator<T>
  {
  private:
    //TBufferedAllocator<> node_all;
    //TMovedMols *current;
  public:
    T* allocate(size_t n, const void * hint=0)
    {
      std::cout << "_TLocalSetAllocator::allocate called, size="<<n <<std::endl;
      return std::allocator<T>::alocate(n, hint);
    }
    
    void deallocate(TMovedMols* p, size_t n)
    {
      std::cout << "_TLocalSetAllocator::deallocate called, size="<<n <<std::endl;
      std::allocator<T>::dealocate(p, n);
    }
    
    void SetCurrent(TMovedMols *Acurrent)
    {
      //current=Acurrent;
    }
    
    template<class _Other>
    struct rebind
    {
      typedef TBufferedAllocator<_Other> other; 
    };
  };
  
  typedef std::set<_TMovedMols> my_set_t;
  // std::less <_TMovedMols>, TLocalSetAllocator<_TMovedMols> 

  class foo {};
  
int main ()
{
  my_set_t myset;
  my_set_t::iterator it;
  std::pair<my_set_t::iterator,bool> ret;
  std::vector<foo, TBufferedAllocator<foo> > v_foo;
  //
  v_foo.get_allocator().BufReserve(100);
  //myset.get_allocator().BufReserve(100);
  v_foo.reserve(10);
  // set some initial values:
  for (int i=1; i<=5; i++) 
    myset.insert(i*10);    // set: 10 20 30 40 50
  ret = myset.insert(20);               // no new element inserted
  if (ret.second==false) 
    it=ret.first;  // "it" now points to element 20
  myset.insert (it,25);                 // max efficiency inserting
  myset.insert (it,24);                 // max efficiency inserting
  myset.insert (it,26);                 // no max efficiency inserting
  //
  myset.clear();
  int myints[]= {5,10,15};              // 10 already in set, not inserted
  myset.insert (myints,myints+3);
  std::cout << "myset contains:";
  for (it=myset.begin(); it!=myset.end(); it++)
    std::cout << " " << it->UniqueMolID<< ", "<<it->Direction;
  std::cout << std::endl;
  return 0;
}


Smth like that but it doesn't work :(
How properly to create allocator-with-states?

Same as any other object: pass an argument to its constructor.




Don't get. How then can i call that constructor if i know that instantiation done inside stl and original object never can be accessed?
Last edited on

Don't get. How then can i call that constructor if i know that instantiation done inside stl and original object never can be accessed?

Understood now. Container's constructors allow to do so.
Topic archived. No new replies allowed.