Why do compilers allow a dispenser of a different type of value than the container used

It seems that the requirements of the C ++ STL container are that the provided dispenser type value_type will be the same as the STL container value_type

Required: allocator_- type :: value_type is the same as X :: value_type.

However, the following code, which uses a row vector, but with a distributor for doubles, works fine on VS 2012 and g ++ 4.4.7. In g ++, valgrind also does not cause errors.

int main() { typedef vector<std::string, std::allocator<double> > StringList; StringList s; for(int i=0; i < 100; i++){ stringstream ss; ss << i; s.push_back(ss.str()); } for(StringList::iterator it = s.begin(); it != s.end(); ++it) { cout << *it << " "; } cout << endl; return 0; } 

I am assuming that the dispenser returns internally to the dispenser of the type_type of the container (although maybe I'm wrong).

My question is that I am not reading the C ++ specification correctly, and in fact, all containers will always “reorder” the provided allocator to use the type they need? Or this is just normal practice, but not guaranteed.

In fact, can I count on this “function” that the containers will always take any dispenser that I provide (of any type) and make it work for the value_type of this container?

+5
source share
2 answers

If you try to create your code using clang / lib ++ (adding the corresponding includes and using namespace std; ;, you will get:

/ Sources / LLVM / llvm / projects / libcxx / include / vector: 474: 5: error: static_assert failed "Allocator :: value_type must be the same type as the value type" static_assert ((is_same :: value),

Anyway, the standard is really clear on this (in C ++ 11/14 / 1z - but not C ++ 03):

 *Requires:* `allocator_type::value_type` is the same as `X::value_type` 

So, if you try to instantiate vector<std::string, std::allocator<double> > , you get undefined behavior - and it seems to work fine, this is a particularly tedious version of undefined behavior. But actually, it seems, "everything is working fine now"

+4
source

When you write your own dispenser, you can basically use a different value_type parameter in your dispenser, as in your type.

As in C ++ 11, a type type is used to check if a type T can have a allocator_type with which the passed dispenser can be converted. If this conversion is not provided (or the compiler does not validate it), you have undefined behavior.

In MSVC 14.1, conversion is done using simple reordering

  template<class _Other> struct rebind { // convert this type to allocator<_Other> typedef allocator<_Other> other; }; 

So, in MSVC, it really performs internal recovery, since for your last question, I would not rely on this implementation, remaining in this way, of course, not on different compilers. I would also wonder why you would like to rely on it, instead of giving the right type trait?

0
source

Source: https://habr.com/ru/post/1268081/


All Articles