dsharlet
dsharlet

Reputation: 1066

Customizing std::allocator_traits::construct

I would like to customize std::vector behavior to not default-construct the element type (e.g. int), as it is expensive to do this for a large vector.

Looking at this, the only way I can see to do this is to specialize std::allocator_traits<MyAllocator>::construct. However, this doesn't seem to be possible, because the specialization must be in the same namespace as the original declaration.

Putting a specialization in namespace std already doesn't seem right. And it's actually worse than that, because the STL implementation I am using actually puts std::allocator_traits in namespace std::__u (and that surely varies across STL implementations), so it seems very wrong to do this.

This is confusing because it seems like std::allocator_traits is designed to allow specialization, but I can't figure out how to actually do it. Is this simply a bad idea? If so, is there some other way to solve the problem (avoiding default construction of elements in STL containers)?

Upvotes: 3

Views: 826

Answers (2)

Nicol Bolas
Nicol Bolas

Reputation: 473447

Specializing standard library traits classes is not only allowed, it's the main way to provide such functionality. However, in this particular case, it is unnecessary.

The default std::allocator_traits<T>::construct implementation (where T is your allocator type, not the value-type of the container it is being used with) will call the construct member function of T if T has such a function, and it calls placement-new if T doesn't have an appropriate member. So simply give your allocator a construct member and you should be fine.

Upvotes: 4

Phil1970
Phil1970

Reputation: 2623

You should call reserve and not resize. Add element only when the value is known. There is no point to create a vector full of garbage.

std::vector<int> v;
r.reserve(500);
v.push_back(3); // Only 1 constructor is called

If you really don't want to initialize the data but still fill it, then using a struct with a constructor that do not initialize its member should do;

struct unintialized_int
{
    unintialized_int() { /* no initialization */ }
    int uninitialized;
};

std::vector<unintialized_int> v;
v.resize(500);
v[22].uninitialized = 33;

However, I would not recommend that as it can lead to hard to find bugs!
Better to use vector as intended.

By the way to have an impact on performance with trivial type like int, you must have many thousand items or create thousand of vectors.

Some questions to ask yourself:

  • Are you measuring performance on a release build? Debug build can be significantly slower.
  • Have you profiled your application to determine that it is the constructor that cause the slow down? If fact, for trivial types like int, the compiler is probably able to optimize the initialisation to a memset.
  • And are you sure that initialisation have any measurable impact on performance?

Upvotes: -2

Related Questions