The implementation of std::vector
that ships with Visual Studio 2010 and earlier versions has a well known particularity: the resize
method has the following signature (C++03-compliant):
void resize(size_type new_size, value_type value);
instead of the C++11-compliant signature that's been used by the majority of other STL implementations (like gcc's STL or STLport) long before C++11:
void resize(size_type new_size, const value_type& value);
The problem with the first variant is that, in some situations, it will fail to compile if value_type
has an alignment specification:
struct __declspec(align(64)) S { ... };
std::vector<S> v; // error C2719: '_Val': formal parameter with __declspec(align('64')) won't be aligned
This is a well known problem with no satisfactory workaround apart from using a different implementation of std::vector
.
I'm looking for a well-written, well-tested, self-contained and STL-compatible implementation of std::vector
with a MIT-style licence that I could drop into my project as a container of choice for aligned types.
I considered extracting it from STLport or gcc's STL but, being fully standard-compliant, they're both large with many non-trivial dependencies.
(I would be perfectly happy with an implementation of a reasonable subset of std::vector
that would only support push_back
, clear
, capacity
, size
, reserve
, resize
, swap
and array indexing.)
Any ideas?
The guys behind the Eigen library seem to have found a nice workaround for the problem of storing "overly-aligned types" ( as Stephan T. Lavavej call them ) into a std::vector
as implemented in Visual Studio's STL.
Their implementation seems unnecessary complicated (check the sources here and here ) but the main idea is to encapsulate the type that goes into the std::vector
with a thin wrapper:
#include <vector>
template <typename T>
struct wrapper : public T
{
wrapper() {}
wrapper(const T& rhs) : T(rhs) {}
};
struct __declspec(align(64)) S
{
float x, y, z, w;
};
int main()
{
std::vector< wrapper<S> > v; // OK, no C2719 error
return 0;
}
About the implementation in Eigen, I must admit I don't quite understand
Eigen::aligned_allocator_indirection
, EIGEN_WORKAROUND_MSVC_STL_SUPPORT
, Eigen::workaround_msvc_stl_support
, resize
in their partial specialization of std::vector
for the Eigen::aligned_allocator_indirection
allocator... Clues welcome. The point is, this trick works perfectly (as far as I can tell) and I don't see anything wrong with it, apart maybe from the slight inelegance.
The easiest (and best, imho) option would be to provide a free function as an extension to the vector
interface, which does the right thing. The functions you need to implement resize
are all available from the public interface of std::vector
:
#include <vector>
template<class T, class Alloc>
void resize(std::vector<T, Alloc>& v,
typename std::vector<T, Alloc>::size_type new_size, T const& val)
{
if (v.size() < new_size)
v.insert(v.end(), new_size - v.size(), val);
else if (new_size < v.size())
v.erase(v.begin() + new_size, v.end());
}
And for consistency also the single argument version:
template<class T, class Alloc>
void resize(std::vector<T, Alloc>& v,
typename std::vector<T, Alloc>::size_type new_size)
{
v.resize(new_size); // simply forward
}
If you, however, just want to drop-in the new vector and never worry about free or member function, another option is to simply subclass std::vector
:
#include <vector>
#include <memory>
template<class T, class Alloc = std::allocator<T>>
class myvector
: public std::vector<T, Alloc>
{
typedef std::vector<T, Alloc> base;
public:
typedef typename base::size_type size_type;
void resize(size_type new_size){
base::resize(new_size);
}
void resize(size_type new_size, T const& val){
if (this->size() < new_size)
this->insert(this->end(), new_size - this->size(), val);
else if (new_size < this->size())
this->erase(this->begin() + new_size, this->end());
}
};
Note that I also provided the single argument version of resize
, since the two argument version would hide all base-class versions. Also note that I needed to prefix all member function calls with this->
, since they are dependent on the base class std::vector
, and as such on the template arguments.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.