What are the limitations on std :: map <K, V> :: mapped_type?

Consider this code:

#include <iostream>
#include <map>
#include <string>

using namespace std;

class Foo {
  public:
  Foo() {}
  virtual ~Foo() {}

  void DoFoo() { cout << "Foo" << endl; }

  Foo(const Foo&) = delete;
  void operator=(const Foo&) = delete;
};

int main() {
  map<string, Foo> m;
  m["Foo"].DoFoo();
}

      

Both g ++ and clang ++ crash when using a version libstdc++

earlier than 4.8. The exact clang ++ error message is:

In the file included in / usr / include / c ++ / 4.6 / iostream: 39:

In the file included in / usr / include / c ++ / 4.6 / ostream: 39:

In the file included in / usr / include / c ++ / 4.6 / ios: 40:

In the file included in / usr / include / c ++ / 4.6 / bits / char_traits.h: 40:

In the file included in / usr / include / c ++ / 4.6 / bits / stl_algobase.h: 65:

/usr/include/C++/4.6/bits/stl_pair.h: 121: 35: error: call to delete constructor 'Foo'

: first (std :: forward <_U1> (__ x)), second (__ y) {}

^ ~~~

/usr/include/C++/4.6/bits/stl_pair.h: 267: 14: note: when creating the custom template function 'std :: pair, Foo> :: pair, void>' is requested here

return __pair_type (std :: forward <_T1> (__ x), std :: forward <_T2> (__ y));

^

/usr/include/C++/4.6/bits/stl_map.h: 467: 29: note: when creating a specialized function 'std :: make_pair, Foo>' requested here

__ i = insert (__ i, std :: make_pair (std :: move (__ k), mapped_type ()));

^

21: note: when creating member function 'std :: map, Foo, std :: less>, std :: allocator, Foo →> :: operator []' was requested here

m ["Foo"] DoFoo () ;.

It looks like the constructor is std::pair

trying to use the Foo

copy-constructor, which I think is fair since it Foo

doesn't declare a move constructor. As I expected, providing a default move constructor fixes the problem.

However, compilation succeeds without a move constructor defined when using version libstdc++

4.8 or higher. I am sure that in both cases the compiler is the same and only the version libstdc++

changes. Foo(Foo&&) = delete;

also does not affect the clang's ability to compile correctly in this case.

My question has several aspects:

Why libstdc++

does the old version require the move constructor to be provided by the user in order to use it instead of the copy constructor?

What's different in the new version of the library, which allows it to create a new item (according to the contract operator[]

) without any move / copy constructors or operator=

?

Which implementation matches? What does the standard say about std::map<K, V>::mapped_type

, if anything?

+3


source to share


1 answer


In C ++ 11, [map.access] reads:

T& operator[](const key_type& x);

1 Effects: If there is no key equivalent on the card x

, insert value_type(x, T())

into the card.

2 Required: key_type

Must be CopyInsertable and mapped_type

Must be DefaultInsertable in * This.

3 Returns: a reference to the mapped_type file corresponding to the x in * this.

4 Complexity: logarithmic.



The only requirement for operator[]

on mapped_type

is that it is a DefaultInsertable (basically a DefaultConstructible). If the library does not support non-copyable mapped_type

from operator[]

, then this is an error.

+3


source







All Articles