简体   繁体   中英

Using array as map key: impossible even with custom allocator?

This question is related to these three questions .

I was trying to use a fixed-length array as a key to a std::map , as demonstrated in the non-compiling code below:

#include <cstdlib>
#include <iostream>
#include <map>

typedef char myuuid[ 16 ];

template <class T>
class MyAlloc
{
public:
  typedef T value_type;
  typedef T* pointer;
  typedef T& reference;
  typedef const T* const_pointer;
  typedef const T& const_reference;
  template <class U> struct rebind { typedef MyAlloc<U> other; };
  MyAlloc() {}
  MyAlloc( const MyAlloc& other ) {}
  T* allocate( std::size_t n ) { return static_cast<T*>( std::malloc( n * sizeof( value_type ) ) ); }
  void deallocate( T* p, std::size_t n ) { std::free( p ); }
};

int main( int argc, char* argv[] )
{
  std::map<myuuid, int, std::less<myuuid>, MyAlloc<myuuid> > map;
  myuuid myu;
  map[ myu ] = 5;

  return 0;
}

Momentarily ignoring the custom allocator, if I correctly understand the linked answers, the reason that std::map<myuuid, int> map; myuuid myu; map[myu] = 5; std::map<myuuid, int> map; myuuid myu; map[myu] = 5; fails comes down to the following being impossible:

int main( int argc, char* argv[] )
{
  char a[3];
  char b[3];
  b = a; // Illegal - won't compile
  return 0;
}

Question :

I understand why the above is illegal - but am I correct that this demonstrates the reason why std::map<myuuid, int> map; myuuid myu; map[myu] = 5; std::map<myuuid, int> map; myuuid myu; map[myu] = 5; is illegal?

Question :

I thought I might be able to get away with compiling std::map<myuuid, int> map; myuuid myu; map[myu] = 5; std::map<myuuid, int> map; myuuid myu; map[myu] = 5; if I implemented a custom allocator. I guessed that perhaps the = (assignment) of a myuuid would be "rerouted" to MyAlloc::allocate() , but that was a wild, unreasoned guess, which seems to be false. Is there a way that a custom allocator can be modified to solve the first code-block's compilation error?

I have a half-baked notion that that operator= on myuuid operands could be "rerouted" to the custom allocator, but I don't know if this is true for PODs ( myuuid is just typedef'ed to a POD`).

The compile error is too voluminous to post here, but tellingly, the first error is:

/usr/include/c++/4.8.3/bits/stl_pair.h: In instantiation of \u2018std::pair<_T1, _T2>::pair(const _T1&, const _T2&) [with _T1 = const char [16]; _T2 = int]\u2019:
/usr/include/c++/4.8.3/bits/stl_map.h:469:59:   required from \u2018std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = char [16]; _Tp = int; _Compare = std::less<char [16]>; _Alloc = MyAlloc<char 
[16]>; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = int; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = char [16]]\u2019
main.cpp:27:12:   required from here
/usr/include/c++/4.8.3/bits/stl_pair.h:113:31: error: array used as initializer
       : first(__a), second(__b) { }

Interestingly, error: array used as initializer is the original compile error I was trying to solve from before introducing the custom allocator. So this seems like a recursive problem.

Question :

Can use of an array as a std::map key be pulled off somehow by making use of a custom allocator? (Perhaps there's an optional function I should implement?) Or are the alternatives at the noted links the only solutions? (It was not raised in the answers to those questions, but since custom allocators are a bit esoteric, I thought it was worth a separate question)

Raw C arrays are not well behaved types. You cannot assign them or do a myriad of other things with them you'd want to.

Second, std::less<char[16]> doesn't work.

C++ provides std::array , which is a thin wrapper around a raw C array in a struct .

typedef std::array<char, 16> myuuid;

It even comes with a built in < that does the right thing usually.

So we get:

std::map<myuuid, int> map;

and things work.

std::array has [] and .data() and .size() and .begin() and .end() and generally behaves well.

If you need to convert it to a pointer, just call .data() .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM