How to add to std::map an object with constant field? - c++

Suppose I have the following code:
#include <string>
#include <map>
struct A {
const int value;
A(int value) : value{value} {}
};
int main() {
A a{3};
std::map<std::string, A> myMap;
myMap["Hello"] = a; // Error: Copy assignment operator of 'A' is implicitly deleted because
// field 'value' is of const-qualified type 'const int'.
return 0;
}
Well I understand the error. But I can't override operator= for this type of structure, because it has const int value field. So what should I do?
Commenters here suggest different solutions with their own pros and cons. Let me clear up the behaviour I need.
const int value is constant forever. No tricks or hacks to modify it.
If the key doesn't exist in a map, then assignment means "add pair [key, value] to the map". But if the key exists, then replace the value.
No default creation of A objects. Accessing to map using a key that doesn't exist in a map should throw an error or abort or something. But creating default 'A' objects for an unexisting key is not allowed.
If I understand all the presented solutions, the best thing I can do is to create some wrapper around std::map. How do you think?

Use map::emplace to construct A in-place:
myMap.emplace("Hello", 3);
Demo.
If the key doesn't exist in a map, then assignment means "add pair
[key, value] to the map". But if the key exists, then replace the
value.
As #Serge Ballesta commented, when the key already exists, you need to erase the node from the map and emplace a new node:
const char* key = "Hello";
const int value = 3;
const auto it = myMap.find(key);
if (it != myMap.end())
myMap.erase(it);
myMap.emplace(key, value);

struct A as the value of map, need a constructer and a operator=():
struct A {
const int32_t value;
A(): value(0) {}
A(int32_t value) : value(value) {}
A& operator=(const A& other) {
// this change the value, if don't want change it, ignore this.
// this is an undefined behavior. ignore this.
// const_cast<int32_t&>(value) = other.value;
return *this;
}
};

Related

set default value of unordered map if key doesn't exist

In my program I want that the default value, if a key doesn't exist in my unordered map, is going to be std::numeric_limits<double>::max() Instead of just 0.
my code looks like the following:
class Pair
{
public:
Graph::NodeId node;
bitset<64> bits;
Pair(Graph::NodeId node1, double bits1)
{
node = node1;
bitset<64> temp(bits1);
bits = temp;
}
};
bool operator==(const Pair &P1, const Pair &P2)
{
return P1.node == P2.node && P1.bits == P2.bits;
}
template <>
struct std::hash<Pair>
{
std::size_t operator()(const Pair &pair) const noexcept
{
std::hash<decltype(pair.node)> ihash;
std::hash<decltype(pair.bits)> bhash;
return ihash(pair.node) * 31 + bhash(pair.bits);
}
};
unordered_map<Pair, double> lFunction;
so if I want to access the element lFunction[Pair(3,3)] and the key doesn't exist, there should be the value std::numeric_limits<double>::max().
One possibility would be to create a tiny class for the value type:
class dproxy {
double value_;
public:
dproxy(double value = std::numeric_limits<double>::max())
: value_{value} {}
operator double &() { return value_; }
operator double const &() const { return value_; }
};
std::unordered_map<Pair, dproxy> lFunction;
A default-constructed dproxy will be initialized to std::numeric_limits<double>::max(), and a dproxy will implicitly convert to a (reference to a) double. This can impose limitations if you're doing a lot of implicit conversions otherwise though (e.g., if you had some other function foo that took some other type bar that could be implicitly constructed from a double, foo(lFunction[baz]); would work if lFunction contained doubles, but not if it contained dproxy objects, since an implicit conversion sequence can only use one user-defined conversion).
if I want to access the element lFunction[Pair(3,3)] and the key doesn't exist, there should be the value std::numeric_limits<double>::max().
std::unordered_map::operator[] simply does not work that way. When it needs to insert a new value for a missing key, the new value is always value-initialized, which for numeric types means 0. There is no option to change that behavior in the unordered_map itself. But #JerryCoffin's answer shows you a workaround to take advantage of that behavior so you can define your own default value.
Otherwise, the alternative is to simply not use the map's operator[] at all. Use its find() and emplace() methods instead, eg:
auto getFunctionValue = [&](const Pair &key)
{
auto iter = lFunction.find(key);
if (iter == lFunction.end()) {
iter = lFunction.emplace(key, std::numeric_limits<double>::max()).first;
// or simply:
// return std::numeric_limits<double>::max();
}
return iter->second;
};
//double d = lFunction[Pair(3,3)];
double d = getFunctionValue(Pair(3,3));
...
Or, if you are using C++17 or later, you can use the try_emplace() method instead, eg:
auto getFunctionValue = [&](const Pair &key)
{
return lFunction.try_emplace(key, std::numeric_limits<double>::max()).first->second;
};
//double d = lFunction[Pair(3,3)];
double d = getFunctionValue(Pair(3,3));
...

map with fixed (const) keys and changeable data? [duplicate]

I have a situation, where I would like to have a map that does not allow to add/remove keys after initialization, but the values are allowed to change (thus I cannot simply make the map const). Ie
/*semi-const*/ map<int,int> myMap = initMap();
myMap[1] = 2; // NOT OK, because potentially adds a new key
myMap.at(1) = 2; // OK, because works only if key is present
for (auto & element : myMap) {
element.second = 0; // OK, values may change
}
I could write my own wrapper for std::map, but I have the feeling that it is something not too uncommon, so I wonder if there is already an existing solution.
Is there some standard idiom for a map that does not allow adding/removing keys, while the values may change?
ps: I know that the title alone is a bit vague, because the keys are already const in a map, but I hope it is clear what I mean...
Could you create a wrapper that contains the value that allows the value to be mutated when const and put that in the map instead? Something like:
template<typename T>
class Mutable {
mutable T value;
public:
const Mutable& operator=(const T& v) const { value = v; return *this; }
T& get() const { return value; }
};
Then your map can be of type
const std::map<int, Mutable<int>>
Live demo.
I usually regard this as a pitfall in C++ more than a feature, but, if it fits your application, you can just use pointer values.
#include <map>
#include <memory>
int main(int argc, char ** argv)
{
using namespace std;
const map<int, shared_ptr<int>> myMap = { {1, make_shared<int>(100)} };
// *(myMap[1]) = 2; // Does not compile
*(myMap.at(1)) = 2;
for (auto & element : myMap)
{
*(element.second) = 0;
}
return 0;
}
Which is really just a simpler version of this other answer (obviously you may choose between shared_ptr / unique_ptr as needed).
Containers from the standard library are classes optimized for one usage that are expected to be used as is or included in higher level classes.
Here your requirement (keys fixed after initialization) is not covered by the standart library containers, so you will have to build your own implementation. As it will not be a std::map, you can just implement the operations you need, probably nothing more that operator []...
I understand that you simply want to disable the index access operator so that a user cannot accidentally add a default constructed item to the map. My solution is inspired by Chris Drew's solution but has the added benefit of remaining const correct (i.e. not allowing changing values of the map when the map is const).
Essentially, by disabling default construction you remove the ability to invoke the index access operator provided by std::map. The other methods will remain available since std::map is a class template and member functions won't be evaluated until they are invoked. Hence, std::map::at will work fine but std::map::operator[] will result in a compile-time error.
Inspired by Chris you can use a wrapper on the mapped_type to disable default construction. I took his demo and tweaked it a bit to demonstrate how to disable default construction and used it with std::map rather than a const std::map.
template<typename T>
class RemoveDefaultConstruction {
T value;
public:
RemoveDefaultConstruction() = delete; // The magic is here
RemoveDefaultConstruction(const RemoveDefaultConstruction &other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
RemoveDefaultConstruction(RemoveDefaultConstruction &&other) noexcept(std::is_nothrow_move_constructible<T>::value) = default;
RemoveDefaultConstruction(T &&t) noexcept(std::is_nothrow_constructible<T, decltype(std::forward<T>(t))>::value) :
value{std::forward<T>(t)} {
}
RemoveDefaultConstruction& operator=(const RemoveDefaultConstruction &other) = default;
RemoveDefaultConstruction& operator=(RemoveDefaultConstruction &&other) = default;
RemoveDefaultConstruction& operator=(T &&other) { value = std::move(other); return *this; }
RemoveDefaultConstruction& operator=(T const &other) { value = other; return *this; }
T const &get() const { return value; } // Keep const correctness
T &get() { return value; } // Keep const correctness
};
void update(std::map<int, RemoveDefaultConstruction<int>> &m, int k, int v) { m.at(k) = v; }
void update(std::map<int, RemoveDefaultConstruction<int>> const &m, int k, int v) {
//m.at(k) = v; // ERROR: Cannot change a const value
}
Live Demo
I see 2 options here
Make the map const and use const_cast when changing something
const std::map myMap;
myMap[1] = 2; // NOT OK, because const map
(const_cast&>(myMap)).at(1) = 2; // OK with const_cast
make an wrapper class or derive an custom map that has only read and update existing value methods
I don't think there is an built in way to make an map only with update value, and restrict and insert.

Change custom class value in range based for loop [duplicate]

I have a std::set<Foo>, and I'd like to update some value of
an existing element therein. Note that the value I'm updating does not change the order in the set:
#include <iostream>
#include <set>
#include <utility>
struct Foo {
Foo(int i, int j) : id(i), val(j) {}
int id;
int val;
bool operator<(const Foo& other) const {
return id < other.id;
}
};
typedef std::set<Foo> Set;
void update(Set& s, Foo f) {
std::pair<Set::iterator, bool> p = s.insert(f);
bool alreadyThere = p.second;
if (alreadyThere)
p.first->val += f.val; // error: assignment of data-member
// ‘Foo::val’ in read-only structure
}
int main(int argc, char** argv){
Set s;
update(s, Foo(1, 10));
update(s, Foo(1, 5));
// Now there should be one Foo object with val==15 in the set.
return 0;
}
Is there any concise way to do this? Or do I have to check if the element is already there, and if so, remove it, add the value and re-insert?
Since val is not involved in comparison, it could be declared mutable
struct Foo {
Foo(int i, int j) : id(i), val(j) {}
int id;
mutable int val;
bool operator<(const Foo& other) const {
return id < other.id;
}
};
This implies that the value of val may change in a logically-const Foo, which means that it shouldn't affect other comparison operators etc.
Or you could just remove and insert, that takes O(1) additional time (compared to accessing and modifying) if insertion uses the position just before just after the old one as the hint.
Something like:
bool alreadyThere = !p.second; // you forgot the !
if (alreadyThere)
{
Set::iterator hint = p.first;
hint++;
s.erase(p.first);
s.insert(hint, f);
}
Don't try to solve this problem by working around the const-ness of items in a set. Instead, why not use map, which already expresses the key-value relationship you are modeling and provides easy ways to update existing elements.
Make val mutable as:
mutable int val;
Now you can change/modify/mutate val even if foo is const:
void f(const Foo & foo)
{
foo.val = 10; //ok
foo.id = 11; //compilation error - id is not mutable.
}
By the way, from your code, you seem to think that if p.second is true, then the value already existed in the set, and therefore you update the associated value. I think, you got it wrong. It is in fact other way round. The doc at cpluscplus says,
The pair::second element in the pair is set to true if a new element was inserted or false if an element with the same value existed.
which is correct, in my opinion.
However, if you use std::map, your solution would be straightforward:
void update(std::map<int,int> & m, std::pair<int,int> value)
{
m[value.first] += value.second;
}
What does this code do? m[value.first] creates a new entry if the key doesn't exist in the map, and value of the new entry is default value of int which is zero. So it adds value.second to zero. Or else if the key exists, then it simply adds value.second to it. That is, the above code is equivalent to this:
void update(std::map<int,int> & m, std::pair<int,int> value)
{
std::map<int,int>::iterator it = m.find(value);
if ( it != m.end()) //found or not?
it.second += value; //add if found
else
{
m.insert(value); //insert if not found
}
}
But this is too much, isn't it? It's performance is not good. The earlier one is more concise and very performant.
If you know what you're doing (the set elements are not const per se and you're not changing members involved in comparison), then you can just cast away const-ness:
void update(Set& s, Foo f) {
std::pair<Set::iterator, bool> p = s.insert(f);
bool alreadyThere = !p.second;
if (alreadyThere)
{
Foo & item = const_cast<Foo&>(*p.first);
item.val += f.val;
}
}
you can use MAP witch has very fast access to your element if you have KEY . in this case i think using MAP would be better way to achieve fastest speed . STD::MAP

map with const keys but non const values?

I have a situation, where I would like to have a map that does not allow to add/remove keys after initialization, but the values are allowed to change (thus I cannot simply make the map const). Ie
/*semi-const*/ map<int,int> myMap = initMap();
myMap[1] = 2; // NOT OK, because potentially adds a new key
myMap.at(1) = 2; // OK, because works only if key is present
for (auto & element : myMap) {
element.second = 0; // OK, values may change
}
I could write my own wrapper for std::map, but I have the feeling that it is something not too uncommon, so I wonder if there is already an existing solution.
Is there some standard idiom for a map that does not allow adding/removing keys, while the values may change?
ps: I know that the title alone is a bit vague, because the keys are already const in a map, but I hope it is clear what I mean...
Could you create a wrapper that contains the value that allows the value to be mutated when const and put that in the map instead? Something like:
template<typename T>
class Mutable {
mutable T value;
public:
const Mutable& operator=(const T& v) const { value = v; return *this; }
T& get() const { return value; }
};
Then your map can be of type
const std::map<int, Mutable<int>>
Live demo.
I usually regard this as a pitfall in C++ more than a feature, but, if it fits your application, you can just use pointer values.
#include <map>
#include <memory>
int main(int argc, char ** argv)
{
using namespace std;
const map<int, shared_ptr<int>> myMap = { {1, make_shared<int>(100)} };
// *(myMap[1]) = 2; // Does not compile
*(myMap.at(1)) = 2;
for (auto & element : myMap)
{
*(element.second) = 0;
}
return 0;
}
Which is really just a simpler version of this other answer (obviously you may choose between shared_ptr / unique_ptr as needed).
Containers from the standard library are classes optimized for one usage that are expected to be used as is or included in higher level classes.
Here your requirement (keys fixed after initialization) is not covered by the standart library containers, so you will have to build your own implementation. As it will not be a std::map, you can just implement the operations you need, probably nothing more that operator []...
I understand that you simply want to disable the index access operator so that a user cannot accidentally add a default constructed item to the map. My solution is inspired by Chris Drew's solution but has the added benefit of remaining const correct (i.e. not allowing changing values of the map when the map is const).
Essentially, by disabling default construction you remove the ability to invoke the index access operator provided by std::map. The other methods will remain available since std::map is a class template and member functions won't be evaluated until they are invoked. Hence, std::map::at will work fine but std::map::operator[] will result in a compile-time error.
Inspired by Chris you can use a wrapper on the mapped_type to disable default construction. I took his demo and tweaked it a bit to demonstrate how to disable default construction and used it with std::map rather than a const std::map.
template<typename T>
class RemoveDefaultConstruction {
T value;
public:
RemoveDefaultConstruction() = delete; // The magic is here
RemoveDefaultConstruction(const RemoveDefaultConstruction &other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
RemoveDefaultConstruction(RemoveDefaultConstruction &&other) noexcept(std::is_nothrow_move_constructible<T>::value) = default;
RemoveDefaultConstruction(T &&t) noexcept(std::is_nothrow_constructible<T, decltype(std::forward<T>(t))>::value) :
value{std::forward<T>(t)} {
}
RemoveDefaultConstruction& operator=(const RemoveDefaultConstruction &other) = default;
RemoveDefaultConstruction& operator=(RemoveDefaultConstruction &&other) = default;
RemoveDefaultConstruction& operator=(T &&other) { value = std::move(other); return *this; }
RemoveDefaultConstruction& operator=(T const &other) { value = other; return *this; }
T const &get() const { return value; } // Keep const correctness
T &get() { return value; } // Keep const correctness
};
void update(std::map<int, RemoveDefaultConstruction<int>> &m, int k, int v) { m.at(k) = v; }
void update(std::map<int, RemoveDefaultConstruction<int>> const &m, int k, int v) {
//m.at(k) = v; // ERROR: Cannot change a const value
}
Live Demo
I see 2 options here
Make the map const and use const_cast when changing something
const std::map myMap;
myMap[1] = 2; // NOT OK, because const map
(const_cast&>(myMap)).at(1) = 2; // OK with const_cast
make an wrapper class or derive an custom map that has only read and update existing value methods
I don't think there is an built in way to make an map only with update value, and restrict and insert.

Change the const of an element of a struct

I have a pointer to a:
struct KeyValue {
K key;
V value;
}
and I want to return a reference to the same memory location interpreted as a
struct IKeyValue {
const K key;
V value;
}
Is there a clean way to do it in C++11?
The reference to IKeyValue should be valid as long as any reference to the original KeyValue is valid.
The reason I am doing this is because I am implementing a HashTable<K, V> using open addressing. As a consequence I have an array of KeyValue with some of them being fully constructed (key and value constructed) and some of them half constructed (only key constructed to empty_key or tombstone_key). I want the iterators to this structure be used such that it->key can be read but not modified and it->value can be read and modified. And I prefer not to have something such as it->key() and it->value() as it is done in the standard library.
As it seems difficult to do this, I am thinking of another option as suggested by the answers. I can construct an array of IKeyValue inside my HashTable with:
IKeyValue* p = (IKeyValue*)malloc(n * sizeof(IKeyValue));
But then, am I allowed to use emplacement new in order to construct just a key or a value with placement new?
You can provide reference members and a constructor
struct IKeyValue {
const K& key;
V& value;
IKeyValue(KeyValue& x) : key(x.key), value(x.value) {}
};
But as mentioned in the comment, the lifetime management for the referenced instances could become a problem.
In IKeyValue, use accessor functions rather than data fields:
struct IKeyValue {
private:
KeyValue & keyValue;
public:
IKeyValue (KeyValue & keyValue) : keyValue (keyValue) {}
K const & key () const { return keyValue.key; }
V & value () { return keyValue.value; }
V const & value () const { return keyValue.value; }
};
KeyValue kv = ...;
IKeyValue ikv (kv);
... ikv.key (); // returns kv.key;
ikv.value () = ...; // sets kv.value;
You can't , as they are not the same type, nor IKeyValue is a derived class of KeyValue.
You need to redesign your code to use something different, like returning a view of the class instead.
The cleanest way to do this is to make your data members private, and provide getters and setters when needed. From what you wrote, it seems that you want the key to be read-only, and the value to be read-write. So you can do this:
class KeyValue
{
public:
KeyValue(K k, V v) : key(k), value(v) {}
K get_key() const {return key;}
V get_value() const {return value;}
void set_value(V v) {value = v;}
private:
K key;
V value;
};
Now the key can only be set in the constructor, and is read-only from that moment on.
Okay, this is quite a weird solution I'm offering here, and some would argue an abusive one, but if your "Value" is always modifiable, you could do something like:
struct KeyValue {
K key;
mutable V value;
};
and then hold a const KeyValue& where you want to lock in the constness of the key.