Using Std::Map<K,V> Where V Has No Usable Default Constructor

Using std::mapK,V where V has no usable default constructor

You can't make the compiler differentiate between the two uses of operator[], because they are the same thing. Operator[] returns a reference, so the assignment version is just assigning to that reference.

Personally, I never use operator[] for maps for anything but quick and dirty demo code. Use insert() and find() instead. Note that the make_pair() function makes insert easier to use:

m.insert( make_pair( k, v ) );

In C++11, you can also do

m.emplace( k, v );
m.emplace( piecewise_construct, make_tuple(k), make_tuple(the_constructor_arg_of_v) );

even if the copy/move constructor is not supplied.

Why does a class used as a value in a STL map need a default constructor in ...?

operator[] performs a two step process. First it finds or creates a map entry for the given key, then it returns a reference to the value part of the entry so that the calling code can read or write to it.

In the case where entry didn't exist before, the value half of the entry needs to be default constructed before it is assigned to. This is just the way the interface needs to work to be consistent with the case where the entry already existed.

If need to use such a type in a map then you have to avoid the use of operator[] by using find and insert "manually".

Why a default constructor is needed using unordered_map and tuple?

visited_info[rect0] = info0;

well, what do you think this does? It's well-documented that the left-hand side evaluates to a reference to an item stored in the map. If that item wasn't there before, it is default constructed first.

You then use either copy- or move-assignment to update that default-constructed item from the right-hand-side of the expression.

If you want to avoid the default-construct-and-assign operation you're getting now, use emplace instead.


NB. One possible source of confusion is, for example, Python, where MyObj[1] might translate to a __getitem__ call, but MyObj[1]=1 to a __setitem__ call.

In C++, both the left-hand-side and right-hand-side expressions must evaluate to something, without knowing anything about the statement they're in. Hence, the left-hand-side evaluates to a reference which you can either read from or assign to - but the object needs to exist before you can take that reference.

Correct friend definition to give std::map access to private default constructor

First, I would like to correct an important point in your post:

Inside the library the default constructor is required for std::map

You can use std::map<K,T> even if T has no default constructor. See this post. In this case you cannot use operator[] to read & write into the map. You can still do it with other methods:

  • read the map: V value = map.at(key);
  • insert into the map: map.insert(std::make_pair(key, value));.

I strongly advise to do it this way.


That being said, if you really want go down the "private constructor & friend" way, from your error message:

In instantiation of ‘std::pair<_T1, _T2>::pair(/*...*/) [with /*...*/; _T1 = const int; _T2 = Example]’

You can try to friend std::pair<const int, Example>;. As Caleth said in his answer, this might not be portable.

Use Z3::expr as a map value

This is a general issue with map: [] requires an empty constructor for the instance type, see this and this.

(Ugly) Tweak.
You might want to derive a sub-class of map, add a local reference to a z3 context and provide this parameter either through the constructor of map_subclass or a method. Then, you should override [] so that it uses this reference to create a new expr instance with the constructor expr(context &c), instead of attempting to use expr().

My knowledge of z3's internals is limited, but as far as I know this should not break anything.

What happened when call std::map's operator[] or insert

The problem with insert is that make_pair will create a pair of the wrong type so the passed object will need a conversion to a proper pair type to be passed to insert.

Actually in a former version the C++ standard mandated map::operator[] to behave as insert (thus forcing an inefficient implementation). Later the text was relaxed allowing a better implementation.

Note anyway that for standard containers the elements are considered to be "values", i.e. the implementation is free to copy things around and you get no guarantees about how many copies will be made.

You can see the make_pair problem by changing the code to

    mymap2.insert(std::pair<const Key, int>(k, 1));

Longer explanation

The problem is that make_pair will create an std::pair<Key, int> value but insert signature wants instead a const std::pair<const Key, int>& (note that std::map::value_type is a pair with a const first element).

These two types are incompatible and unrelated so to be able to make the call another pair must be created copying both key and value and this is where an extra key duplication occurs.

Even if it could be apparently "logical" that a pair<X, Y> should be directly usable where pair<const X, Y> is expected this is not true in C++ and it's one of the logical problems of the const-correctness concept (it doesn't scale by composition).

How to set your default value in a constructor of iterators? C++

Not going into why you would need a default value, I would suggest to use the default value of the map iterator (which is an invalid iterator)

 typedef typename map<TYPE, TYPE2>::const_iterator map_citer;
const_iterator(map_citer param = map_citer());
//^^^^^^^^^^^

Edit:

Considering your edit, it seems that most logical in your situation would be to overload your constructor. Have two overloads, one that doesn't take anything (do what you think is best in that constructor) and your original one. That should do the trick :)

const_iterator(typename map<TYPE, TYPE2>::const_iterator);
const_iterator();

C++ counting instances / histogram using std::map

Indeed that's how map works: The []-operator is mutating and will create the object of mapped type if it does not exist yet. Since size_t value-initializes to zero, you're all fine.



Related Topics



Leave a reply



Submit