static_vector using aligned_storage

Hi, I'm developing R-tree container for Boost.Geometry. To keep it short, there are containers of Values in leaf nodes. Those containers must have push_back() functionality. For static-size nodes I'm using a container based on boost::array. Unfortunately this means that default constructors of stored Values are called when the container is created. I'd like not to expect that Values have their default ctor implemented. I've implemented an alternative container using boost::aligned_storage. This is just a proof of concept. The code is available here: https://svn.boost.org/svn/boost/sandbox-branches/geometry/index/tests/static... I've searched for this kind of container in Boost since I remember that someone proposed it some time ago but didn't find it anywhere. Is it released somewhere? Maby as a part of some library? If not, would you be so kind and see if my solution should work for any/most popular compiler/platform? I've tested it only on clang. To be specific, won't there be any problems with the memory aligmnent if I use this code for storage: boost::aligned_storage<sizeof(Value) * Capacity> m_storage; this for access: *(reinterpret_cast<Value*>(m_storage.address()) + i); and this for construction new (reinterpret_cast<Value*>(m_storage.address()) + i) Value(value); Regards, Adam

On Dec 12, 2012, at 8:08 AM, Adam Wulkiewicz <adam.wulkiewicz@gmail.com> wrote:
Hi,
I'm developing R-tree container for Boost.Geometry. To keep it short, there are containers of Values in leaf nodes. Those containers must have push_back() functionality. For static-size nodes I'm using a container based on boost::array. Unfortunately this means that default constructors of stored Values are called when the container is created. I'd like not to expect that Values have their default ctor implemented. I've implemented an alternative container using boost::aligned_storage. This is just a proof of concept. The code is available here:
https://svn.boost.org/svn/boost/sandbox-branches/geometry/index/tests/static...
I've searched for this kind of container in Boost since I remember that someone proposed it some time ago but didn't find it anywhere. Is it released somewhere? Maby as a part of some library?
As far as I know, there isn't one in Boost. I wrote one once, but never submitted it for review. BTW, you're missing a bunch of stuff that needs to be there: iterator support, exception safety, swap, etc. This is supposed to be easy in C++11, with the appropriate allocator. [ I say "supposed to be" since I haven't tried it. ] -- Marshall Marshall Clow Idio Software <mailto:mclow.lists@gmail.com> A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait). -- Yu Suzuki

On 12 December 2012 10:22, Marshall Clow <mclow.lists@gmail.com> wrote:
On Dec 12, 2012, at 8:08 AM, Adam Wulkiewicz <adam.wulkiewicz@gmail.com> wrote:
https://svn.boost.org/svn/boost/sandbox-branches/geometry/index/tests/static...
I've searched for this kind of container in Boost since I remember that
someone proposed it some time ago but didn't find it anywhere. Is it released somewhere? Maby as a part of some library?
This is supposed to be easy in C++11, with the appropriate allocator. [ I say "supposed to be" since I haven't tried it. ]
I do not believe it is possible to do so with just an allocator under C++11. :-( I think the best one can do is have a separate (not embedded in the allocator, and hence, not embedded in vector) arena for the space, as in http://home.roadrunner.com/~hinnant/stack_alloc.html. So there is still a need for a static vector class. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

Marshall Clow wrote:
On Dec 12, 2012, at 8:08 AM, Adam Wulkiewicz <adam.wulkiewicz@gmail.com> wrote:
Hi,
I'm developing R-tree container for Boost.Geometry. To keep it short, there are containers of Values in leaf nodes. Those containers must have push_back() functionality. For static-size nodes I'm using a container based on boost::array. Unfortunately this means that default constructors of stored Values are called when the container is created. I'd like not to expect that Values have their default ctor implemented. I've implemented an alternative container using boost::aligned_storage. This is just a proof of concept. The code is available here:
https://svn.boost.org/svn/boost/sandbox-branches/geometry/index/tests/static...
I've searched for this kind of container in Boost since I remember that someone proposed it some time ago but didn't find it anywhere. Is it released somewhere? Maby as a part of some library?
As far as I know, there isn't one in Boost. I wrote one once, but never submitted it for review.
BTW, you're missing a bunch of stuff that needs to be there: iterator support, exception safety, swap, etc.
As I've written, it's a proof of concept no a ready container, but implemented operations are safe. I don't see a way to implement non-throwing swap since I don't want to use some external storage. So swap probably won't be implemented - just copy. Regards, Adam

On 12 December 2012 10:49, Adam Wulkiewicz <adam.wulkiewicz@gmail.com>wrote:
I don't see a way to implement non-throwing swap since I don't want to use some external storage.
It should be non-throwing if the underlying T has a non-throwing move or copy constructor.
So swap probably won't be implemented - just copy.
If you can, make the interface as close as possible to C++11 std::vector (well, maybe not vector<bool>, but other than that...). I would do swap even if it can throw; only provide the basic guarantee if it does throw. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

on Wed Dec 12 2012, Nevin Liber <nevin-AT-eviloverlord.com> wrote:
On 12 December 2012 10:49, Adam Wulkiewicz <adam.wulkiewicz@gmail.com>wrote:
I don't see a way to implement non-throwing swap since I don't want to use some external storage.
It should be non-throwing if the underlying T has a non-throwing move or copy constructor.
So swap probably won't be implemented - just copy.
If you can, make the interface as close as possible to C++11 std::vector (well, maybe not vector<bool>, but other than that...). I would do swap even if it can throw; only provide the basic guarantee if it does throw.
+1 Likewise move. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

2012/12/15 Dave Abrahams <dave@boostpro.com>:
on Wed Dec 12 2012, Nevin Liber <nevin-AT-eviloverlord.com> wrote:
On 12 December 2012 10:49, Adam Wulkiewicz <adam.wulkiewicz@gmail.com>wrote:
So swap probably won't be implemented - just copy.
If you can, make the interface as close as possible to C++11 std::vector (well, maybe not vector<bool>, but other than that...). I would do swap even if it can throw; only provide the basic guarantee if it does throw.
+1 Likewise move.
I assumed that only I'll be using my implementation but I and Andrew have decided that we'll be working on this together. If you want to trace our progress the container is available here: http://svn.boost.org/svn/boost/sandbox/static_vector/ Greater part of the std::vector interface is implemented, except C++11 methods emplace(), emplace_back() and shrink_to_fit(). Regards, Adam

Yes, I had proposed StaticVector. Here is the repository: https://github.com/ahundt/Boost.StaticVector Here is a link to the original discussion via google groups: https://groups.google.com/d/topic/boost-developers-archive/4n1QuJyKTTk/discu... I would be interested in working with you to complete either my version or yours. Did you have any thoughts or questions regarding my implementation? There are a few items related to my implementation on the github ticket list that came from the discussion thread that need resolving before the next round, but nothing too bad. Cheers! Andrew Hundt On Wed, Dec 12, 2012 at 11:08 AM, Adam Wulkiewicz <adam.wulkiewicz@gmail.com
wrote:
Hi,
I'm developing R-tree container for Boost.Geometry. To keep it short, there are containers of Values in leaf nodes. Those containers must have push_back() functionality. For static-size nodes I'm using a container based on boost::array. Unfortunately this means that default constructors of stored Values are called when the container is created. I'd like not to expect that Values have their default ctor implemented. I've implemented an alternative container using boost::aligned_storage. This is just a proof of concept. The code is available here:
https://svn.boost.org/svn/**boost/sandbox-branches/** geometry/index/tests/static_**vector.cpp<https://svn.boost.org/svn/boost/sandbox-branches/geometry/index/tests/static_vector.cpp>
I've searched for this kind of container in Boost since I remember that someone proposed it some time ago but didn't find it anywhere. Is it released somewhere? Maby as a part of some library?
If not, would you be so kind and see if my solution should work for any/most popular compiler/platform? I've tested it only on clang.
To be specific, won't there be any problems with the memory aligmnent if I use this code for storage:
boost::aligned_storage<sizeof(**Value) * Capacity> m_storage;
this for access:
*(reinterpret_cast<Value*>(m_**storage.address()) + i);
and this for construction
new (reinterpret_cast<Value*>(m_**storage.address()) + i) Value(value);
Regards, Adam
______________________________**_________________ Unsubscribe & other changes: http://lists.boost.org/** mailman/listinfo.cgi/boost<http://lists.boost.org/mailman/listinfo.cgi/boost>

Andrew Hundt wrote:
Yes, I had proposed StaticVector.
Here is the repository: https://github.com/ahundt/Boost.StaticVector
Here is a link to the original discussion via google groups: https://groups.google.com/d/topic/boost-developers-archive/4n1QuJyKTTk/discu...
I would be interested in working with you to complete either my version or yours. Did you have any thoughts or questions regarding my implementation? There are a few items related to my implementation on the github ticket list that came from the discussion thread that need resolving before the next round, but nothing too bad.
Yes, a few things regarding the interface. I see that the most nagging thing is asserts vs. exceptions issue. I remember that there were quite a discussion about it. Personally I'd like to have exception thrown only in at(). Only this method throws out_of_range exception in std::vector and boost::array. So operator[], pop_back(), erase() shouldn't throw IMO. The problem is with vector's methods which may throw bad_alloc exception, like push_back() or insert(). I think that in general we shouldn't provide mechanisms (throw exceptions) which majority of users wouldn't need. So I see a few possible solutions: 1. Leave static_vector as it is now, throwing exceptions. 2. Make error handling dependent on some macro e.g. BOOST_STATIC_VECTOR_USE_EXCEPTIONS 3. Use slightly different class interface and take additional template parameter: static_vector<T, N, ErrHandling = use_asserts> 4. Use asserts in static_vector and provide a wrapper throwing exceptions. Or if people are concerned about the efficiency, implement a base class and derive both implementations from it. I'd prefer everything besides 1. The rest are details. For example, I'd consider simplifying the interface and moving it closer to vector than array, e.g. making capacity() non-static or removing full(). I don't know if methods returning pointers to internal elements (data() and c_array()) are necessary in resizable container, especially if those are really aligned_storages. I'd rather hide those. Also, I don't know if fill() and assign() is needed in this kind of container, but those certainly don't harm anyone. Regards, Adam

On 12 December 2012 15:39, Adam Wulkiewicz <adam.wulkiewicz@gmail.com>wrote:
Personally I'd like to have exception thrown only in at(). Only this method throws out_of_range exception in std::vector and boost::array. So operator[], pop_back(), erase() shouldn't throw IMO. The problem is with vector's methods which may throw bad_alloc exception, like push_back() or insert(). I think that in general we shouldn't provide mechanisms (throw exceptions) which majority of users wouldn't need. So I see a few possible solutions: 1. Leave static_vector as it is now, throwing exceptions. 2. Make error handling dependent on some macro e.g. BOOST_STATIC_VECTOR_USE_**EXCEPTIONS 3. Use slightly different class interface and take additional template parameter: static_vector<T, N, ErrHandling = use_asserts> 4. Use asserts in static_vector and provide a wrapper throwing exceptions. Or if people are concerned about the efficiency, implement a base class and derive both implementations from it.
Another possible solution is to fall back on an allocator if there isn't enough room in the embedded storage. The signature would be something like static_vector<T, N, A = std::allocator<T>> And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the responsibility of the allocator, not static_vector, to throw or not throw. I don't know if methods returning pointers to internal elements (data() and
c_array()) are necessary in resizable container, especially if those are really aligned_storages.
data() certainly is. Again, I believe the interface should be as close to a superset of C++11 std::vector as possible. I know I'd like to use it as a drop-in replacement for std::vector. Every arbitrary difference makes it a less useful class. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

On Wed, Dec 12, 2012 at 11:57 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
Another possible solution is to fall back on an allocator if there isn't enough room in the embedded storage. The signature would be something like
static_vector<T, N, A = std::allocator<T>>
And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the responsibility of the allocator, not static_vector, to throw or not throw.
That'd make it more like a hybrid_vector, but it's certainly a good idea. It's like a string with a small string optimization. -- Olaf

On Dec 12, 2012, at 3:26 PM, Olaf van der Spek <ml@vdspek.org> wrote:
On Wed, Dec 12, 2012 at 11:57 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
Another possible solution is to fall back on an allocator if there isn't enough room in the embedded storage. The signature would be something like
static_vector<T, N, A = std::allocator<T>>
And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the responsibility of the allocator, not static_vector, to throw or not throw.
That'd make it more like a hybrid_vector, but it's certainly a good idea. It's like a string with a small string optimization.
To me, that's a different container. -- Marshall Marshall Clow Idio Software <mailto:mclow.lists@gmail.com> A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait). -- Yu Suzuki

On 12 December 2012 18:30, Marshall Clow <mclow.lists@gmail.com> wrote:
On Dec 12, 2012, at 3:26 PM, Olaf van der Spek <ml@vdspek.org> wrote:
On Wed, Dec 12, 2012 at 11:57 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
static_vector<T, N, A = std::allocator<T>>
And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the responsibility of the allocator, not static_vector, to throw or not throw.
To me, that's a different container.
Why? How is it behaviorally any different, assuming you give it a null_allocator? -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

Nevin Liber wrote:
On 12 December 2012 18:30, Marshall Clow <mclow.lists@gmail.com> wrote:
On Dec 12, 2012, at 3:26 PM, Olaf van der Spek <ml@vdspek.org> wrote:
On Wed, Dec 12, 2012 at 11:57 PM, Nevin Liber <nevin@eviloverlord.com> wrote:
static_vector<T, N, A = std::allocator<T>>
And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the responsibility of the allocator, not static_vector, to throw or not throw.
To me, that's a different container.
Why? How is it behaviorally any different, assuming you give it a null_allocator?
I agree with Marshall. You can understand 'hybrid' in at least two ways. As I understand it hybrid_vector would have some static storage and allocate new memory only if the number of elements is too big. If Alloc parameter were used then your implementation of a static_vector could become a simple static_vector or a hybrid_vector (or a vector depends on implementation). This kind of container may be simply implemented on top of those containers. What is more, probably only the minority of users will find a use case for it. And the rest will just take a simple static_vector and build a container they need. Regards, Adam

On Wed, Dec 12, 2012 at 7:30 PM, Marshall Clow <mclow.lists@gmail.com>wrote:
On Dec 12, 2012, at 3:26 PM, Olaf van der Spek <ml@vdspek.org> wrote:
Another possible solution is to fall back on an allocator if there isn't enough room in the embedded storage. The signature would be something
On Wed, Dec 12, 2012 at 11:57 PM, Nevin Liber <nevin@eviloverlord.com> wrote: like
static_vector<T, N, A = std::allocator<T>>
And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the
responsibility
of the allocator, not static_vector, to throw or not throw.
That'd make it more like a hybrid_vector, but it's certainly a good idea. It's like a string with a small string optimization.
To me, that's a different container.
-- Marshall
And in fact it *is* a different container. Since the allocator is part of the type, it is a different type. :-) For once, having the allocator as part of the type is a good thing. I posit: 1. we want a hybrid "small string optimization" vector anyhow - I think it would be useful in many places 2. thus assume we have hybrid_vector 3. would we then want static_vector to be different, or just a typedef of hybrid_vector with a particular null_allocator? Tony

on Thu Dec 13 2012, Gottlob Frege <gottlobfrege-AT-gmail.com> wrote:
On Wed, Dec 12, 2012 at 7:30 PM, Marshall Clow <mclow.lists@gmail.com>wrote:
On Dec 12, 2012, at 3:26 PM, Olaf van der Spek <ml@vdspek.org> wrote:
Another possible solution is to fall back on an allocator if there isn't enough room in the embedded storage. The signature would be something
On Wed, Dec 12, 2012 at 11:57 PM, Nevin Liber <nevin@eviloverlord.com> wrote: like
static_vector<T, N, A = std::allocator<T>>
And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the
responsibility
of the allocator, not static_vector, to throw or not throw.
That'd make it more like a hybrid_vector, but it's certainly a good idea. It's like a string with a small string optimization.
To me, that's a different container.
-- Marshall
And in fact it *is* a different container. Since the allocator is part of the type, it is a different type. :-) For once, having the allocator as part of the type is a good thing.
I posit:
1. we want a hybrid "small string optimization" vector anyhow - I think it would be useful in many places 2. thus assume we have hybrid_vector 3. would we then want static_vector to be different, or just a typedef of hybrid_vector with a particular null_allocator?
Hmm, it will be interesting to see how this works. Now that the weasel-wording is gone, the allocator's pointer type, etc., have specific meanings that might not be compatible with stack memory. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

Dave Abrahams wrote:
Hmm, it will be interesting to see how this works. Now that the weasel-wording is gone, the allocator's pointer type, etc., have specific meanings that might not be compatible with stack memory.
Could you please elaborate? Isn't it always a pointer to a type passed to the allocator? How it may be treated differently for stack memory? Regards, Adam

On Tue, Dec 18, 2012 at 12:29 AM, Adam Wulkiewicz <adam.wulkiewicz@gmail.com> wrote:
Dave Abrahams wrote:
Hmm, it will be interesting to see how this works. Now that the weasel-wording is gone, the allocator's pointer type, etc., have specific meanings that might not be compatible with stack memory.
Could you please elaborate? Isn't it always a pointer to a type passed to the allocator? How it may be treated differently for stack memory?
In theory it might be a street address that stores a certain value. In practise it's probably not but I don't think it's guaranteed to be T*. -- Olaf

Olaf van der Spek wrote:
Could you please elaborate? Isn't it always a pointer to a type passed to the allocator? How it may be treated differently for stack memory?
In theory it might be a street address that stores a certain value. In practise it's probably not but I don't think it's guaranteed to be T*.
Ok, sorry for my question. It seems it needs to satisfy RandomAccesIterator concept. The allocator_type and pointers might be defined as thin wrappers if the pointer is different than value_type*. This however only be needed for data() method. Am I right? Btw, how is data() defined? I've found only an info that it should return value_type*. This of course won't work for a hybrid_vector. Or maby it should return pointer type (like in VS2012 btw)? But then what is the purpose of this method? Regards, Adam

On 17 December 2012 19:39, Adam Wulkiewicz <adam.wulkiewicz@gmail.com>wrote:
Btw, how is data() defined?
According to the latest draft of the standard, n3485 23.3.6.1, it returns a T* (or a const T* for the const member version); this is the same as value_type*.
This of course won't work for a hybrid_vector.
Why not?
But then what is the purpose of this method?
To get to the buffer for passing to C routines, usually. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

2012/12/18 Nevin Liber <nevin@eviloverlord.com>:
On 17 December 2012 19:39, Adam Wulkiewicz <adam.wulkiewicz@gmail.com>wrote:
Btw, how is data() defined?
According to the latest draft of the standard, n3485 23.3.6.1, it returns a T* (or a const T* for the const member version); this is the same as value_type*.
This of course won't work for a hybrid_vector.
Why not?
I assumed that in the allocated memory the hybrid_vector stores only elements exceeding the static storage. In this case it would store them in two different places - static storage and allocated one. The overall memory wouldn't be continuous. It would work, if after the static storage overflow and the first allocation, elements were moved to the newly allocated memory. I don't know however if this isn't too big penalty.
But then what is the purpose of this method?
To get to the buffer for passing to C routines, usually.
Yes I understand this. My question is regarding the case when data() returns Alloc::pointer (I believe this is the case in MS implementation). Regards, Adam

On 17 December 2012 22:45, Adam Wulkiewicz <adam.wulkiewicz@gmail.com>wrote:
I assumed that in the allocated memory the hybrid_vector stores only elements exceeding the static storage. In this case it would store them in two different places - static storage and allocated one.
I hope not. One of the properties of vector is that the space is contiguous. If the current storage (whether embedded or allocated) capacity is exceeded, allocate new space, move-if-noexcept or copy the elements from the old space to the new space (say, via std::move_if_noexcept), then deallocate the old space if and only if it was originally allocated.
It would work, if after the static storage overflow and the first allocation, elements were moved to the newly allocated memory. I don't know however if this isn't too big penalty.
It isn't any different than the normal "penalty" for vector.
Yes I understand this. My question is regarding the case when data() returns Alloc::pointer (I believe this is the case in MS implementation).
Sounds like a bug. The standard is quite clear that data() returns a T*, not Alloc::pointer. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

Gottlob Frege wrote:
And in fact it *is* a different container. Since the allocator is part of the type, it is a different type. :-) For once, having the allocator as part of the type is a good thing.
I posit:
1. we want a hybrid "small string optimization" vector anyhow - I think it would be useful in many places 2. thus assume we have hybrid_vector 3. would we then want static_vector to be different, or just a typedef of hybrid_vector with a particular null_allocator?
I must admit that this solution is the most elegant. Do you think that using boost::vector with our container be a good solution for a hybrid_vector for no null_allocator? Or that it is inevitable to reimplement the vector part and handle an allocator by ourselves? I'd choose the former since it wouldn't be reinventing the wheel. But maby you, more experienced Boosters are aware of some issues which could make it impossible? Regards, Adam

2012/12/12 Nevin Liber <nevin@eviloverlord.com>
On 12 December 2012 15:39, Adam Wulkiewicz <adam.wulkiewicz@gmail.com
wrote:
Personally I'd like to have exception thrown only in at(). Only this method throws out_of_range exception in std::vector and boost::array. So operator[], pop_back(), erase() shouldn't throw IMO. The problem is with vector's methods which may throw bad_alloc exception, like push_back() or insert(). I think that in general we shouldn't provide mechanisms (throw exceptions) which majority of users wouldn't need. So I see a few possible solutions: 1. Leave static_vector as it is now, throwing exceptions. 2. Make error handling dependent on some macro e.g. BOOST_STATIC_VECTOR_USE_**EXCEPTIONS 3. Use slightly different class interface and take additional template parameter: static_vector<T, N, ErrHandling = use_asserts> 4. Use asserts in static_vector and provide a wrapper throwing exceptions. Or if people are concerned about the efficiency, implement a base class and derive both implementations from it.
Another possible solution is to fall back on an allocator if there isn't enough room in the embedded storage. The signature would be something like
static_vector<T, N, A = std::allocator<T>>
And you could provide null_allocator_assert and null_allocator_throw as options (or make one of those the default), as it is now the responsibility of the allocator, not static_vector, to throw or not throw.
+1 I like the simplicity and flexibility of this approach. And I'd add a null_allocator_unchecked for performace-critical cases ;) Regards, Kris

On Dec 12, 2012, at 1:39 PM, Adam Wulkiewicz <adam.wulkiewicz@gmail.com> wrote:
Andrew Hundt wrote:
Yes, I had proposed StaticVector.
Here is the repository: https://github.com/ahundt/Boost.StaticVector
Here is a link to the original discussion via google groups: https://groups.google.com/d/topic/boost-developers-archive/4n1QuJyKTTk/discu...
I would be interested in working with you to complete either my version or yours. Did you have any thoughts or questions regarding my implementation? There are a few items related to my implementation on the github ticket list that came from the discussion thread that need resolving before the next round, but nothing too bad.
Yes, a few things regarding the interface.
I see that the most nagging thing is asserts vs. exceptions issue. I remember that there were quite a discussion about it.
Personally I'd like to have exception thrown only in at(). Only this method throws out_of_range exception in std::vector and boost::array. So operator[], pop_back(), erase() shouldn't throw IMO. The problem is with vector's methods which may throw bad_alloc exception, like push_back() or insert(). I think that in general we shouldn't provide mechanisms (throw exceptions) which majority of users wouldn't need. So I see a few possible solutions: 1. Leave static_vector as it is now, throwing exceptions. 2. Make error handling dependent on some macro e.g. BOOST_STATIC_VECTOR_USE_EXCEPTIONS 3. Use slightly different class interface and take additional template parameter: static_vector<T, N, ErrHandling = use_asserts> 4. Use asserts in static_vector and provide a wrapper throwing exceptions. Or if people are concerned about the efficiency, implement a base class and derive both implementations from it.
I'd prefer everything besides 1.
I would like to see static_vector throw an exception if you try to put too much data in it. To me, this is analogous to not being able to allocate memory in std::vector::push_back. For operator [], no exception. -- just like vector. For at (), throw std:: out_of_range -- just like vector
The rest are details.
For example, I'd consider simplifying the interface and moving it closer to vector than array, e.g. making capacity() non-static or removing full().
I don't know if methods returning pointers to internal elements (data() and c_array()) are necessary in resizable container, especially if those are really aligned_storages. I'd rather hide those. Also, I don't know if fill() and assign() is needed in this kind of container, but those certainly don't harm anyone.
data() is nice for passing to legacy (aka "C") interfaces. -- Marshall Marshall Clow Idio Software <mailto:mclow.lists@gmail.com> A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait). -- Yu Suzuki

Andrew Hundt wrote:
Yes, I had proposed StaticVector.
Here is the repository: https://github.com/ahundt/Boost.StaticVector
Here is a link to the original discussion via google groups: https://groups.google.com/d/topic/boost-developers-archive/4n1QuJyKTTk/discu...
I would be interested in working with you to complete either my version or yours. Did you have any thoughts or questions regarding my implementation? There are a few items related to my implementation on the github ticket list that came from the discussion thread that need resolving before the next round, but nothing too bad.
Ok, I've moved my implementation here, if you like to check it out: https://svn.boost.org/svn/boost/sandbox-branches/geometry/index/boost/geomet... This is all I need in my use case (I don't need insert() or erase()). Later if the official one is finished I'll probably use it instead of this one. Regards, Adam
participants (8)
-
Adam Wulkiewicz
-
Andrew Hundt
-
Dave Abrahams
-
Gottlob Frege
-
Krzysztof Czainski
-
Marshall Clow
-
Nevin Liber
-
Olaf van der Spek