i got some issues trying to put the values of my vector in a new map (maMap)
If someone could explain me what contain my ItemIterator or how to do...
map<std::string,Employee*> Entreprise::convertiVectorMap() const
{
map<std::string,Employee*> maMap;
vector<Employee*>::const_iterator ItemIterator;
for(ItemIterator = vector_employe.begin(); ItemIterator != vector_employe.end(); ItemIterator++)
{
maMap.insert(std::pair<string,Employee*>(ItemIterator->getNom(),ItemIterator));
}
}
Your map is of <std::string, Employee*>, but you are trying to add an iterator as the second element of the pair. You need to dereference the iterator to get the Employee pointer.
maMap.insert(std::pair<string,Employee*>((*ItemIterator)->getNom(), *ItemIterator));
Or to save from dereferencing the same iterator twice, you could just use a range based for loop. As #CaptainObvlious mentions, you can also use std::make_pair to add to your map.
for(auto const employee: vector_employe)
{
maMap.insert(std::make_pair(employee->getNom(), employee));
}
You forgot to derefrence your iterator:
maMap.insert(std::pair<string,Employee*>((*ItemIterator)->getNom(),*ItemIterator));
And since everyone asks for a revamped version of your code here we go:
map<std::string,Employee*> Entreprise::convertiVectorMap() const
{
map<std::string,Employee*> maMap;
for(vector<Employee*>::const_iterator ItemIterator = vector_employe.cbegin(),
ItemIteratorEnd = vector_employe.cend();
ItmeIterator != ItemIteratorEnd; ++ItemIterator)
{
Employee* ptr = *ItemIterator;
maMap.insert(std::make_pair(ptr->getNom(),ptr));
}
}
You can also use ranged based for if you're at least in C++11.
Related
I have a class Normal defined as:
class Normal
{
bool value;
float time;
public:
Normal(bool val,float time): value(val),time(time) {}
}
Also, I have declared a map variable as:
map<string,Normal> myMap;
Now I want to insert an data into this map.
Is this way of inserting correct?
Normal temp(true,45.04);
myMap.insert(pair<string,Normal>("one",temp));
or
myMap["one"]=temp;
How should i insert data into the map?
In C++03 :
myMap.insert(std::make_pair(
"one",
Normal(true, 45.04)
));
In C++11 :
m.emplace(std::piecewise_construct,
std::forward_as_tuple("one"),
std::forward_as_tuple(true, 45.04)
);
Both avoid default-constructing a key-value pair inside operator[] and then overwriting it.
Use this code
Normal *temp = new Normal(true,45.9);
mymap.insert(make_pair("one",temp));
avoid shallow copy since pointer is involved.
EDIT: Use insert function to insert data in map. Index is not the best way. specially when u r accessing
See this link for details
In STL maps, is it better to use map::insert than []?
EDIT2: For deletion,use the below code.
for(std::map<string, Normal*>::iterator itr = mymap.begin();it != mymap.end();)
{
if(it->second != NULL)
{
delete (it->second);
(it->second) = NULL;
it=mymap.erase(it);
}
else
{
++it;
}
}
In my program, I have classes I use for handling projectiles in a game.
class Projectile
{
bool IsActive;
bool GetActive();
//....
};
class Game
{
std::vector<Projectile*> ProjectilesToUpdate;
//....
};
Of course, there is more to it than that, however I'm trying to stay relevant to my current problem.
I want to use std::sort to make it so that all projectiles where IsActive == true are at the far beginning and that any projectile which isn't active is at the very end.
How would I go about doing this?
Basically, you want to create a partition:
std::partition(std::begin(ProjectilesToUpdate),
std::end(ProjectilesToUpdate),
[](Projectile const* p) { return p->GetActive(); }
);
As for the subsidiary questions:
I had to remove the "const" part in the code to make it compile.
That's because your GetActive() method should be const:
bool GetActive() const { return IsActive; }
See Meaning of "const" last in a C++ method declaration?
how can I use this to delete every single object (and pointer to object) that is no longer needed?
You could use smart pointers (such as std::shared_ptr) and no longer care about delete. Thus you could use the Erase–remove idiom as follow:
std::vector<std::shared_ptr<Projectile>> ProjectilesToUpdate;
// :
// :
auto it = std::remove_if(
std::begin(ProjectilesToUpdate),
std::end(ProjectilesToUpdate),
[](std::shared_ptr<Projectile> const& p) { return !p->GetActive(); } // mind the negation
);
ProjectilesToUpdate.erase(it, std::end(ProjectilesToUpdate));
Related question: What is a smart pointer and when should I use one?
If you don't want to use smart pointers, you could use the returned iterator which point to the first element of the second group (i.e. the non active ones) and iterate until the end of the array:
auto begin = std::begin(ProjectilesToUpdate);
auto end = std::end(ProjectilesToUpdate);
auto start = std::partition(begin, end,
[](Projectile const* p) { return p->GetActive(); }
);
for (auto it = start; it != end; ++it) {
delete *it;
}
ProjectilesToUpdate.erase(start, end);
Note that I'm not calling erase inside the loop since it invalidates iterators.
And of course, this last solution is more complex than using smart pointers.
in java, I sometimes do this
Map<String, POJO> objmap = new HashMap<String, POJO>();
POJO obj = null;
if ((obj = objMap.get(key)) == null) {
obj = new POJO();
objMap.put(key, obj);
}
obj.setName("something");
obj.setAddress("yeah");
What is the best practice to do similar thing in c++ with std::map?
to create a obj in map if not exist, then update its properties?
Like this:
void insert_or_update(const K & k, const T & t, std::map<K, T> & m)
{
auto p = m.insert(std::make_pair(k, t));
if (!p.second) p.first->second = t;
}
Or:
m[k] = t;
The latter requires T to be default-constructible and assignable.
In C++17 you can also say:
m.insert_or_assign(k, t);
This has fewer restrictions than the above construction and returns information on whether the insertion took place, as well as the iterator to the element.
You want to use the insert function, it returns an iterator and a boolean regarding whether a new object was inserted:
something like this:
typedef map<int,void*> M;
M m;
auto insertion = m.insert(M::value_type(0,nullptr));
if (insertion.second) {
insertion.first->second = new... (// allocate your item or whatever, this is the iterator to it)
}
You can write objmap[key] = value.
See: http://www.cplusplus.com/reference/map/map/operator[]/
std::map<std::string, POJO> mapStr2Pojo;
mapStr2Pojo["something"].setName("something");
mapStr2Pojo["something"].setAddress("yeah");
std::map<>'s operation[] inserts the object if it doesn't find it.
the insertion operation checks whether each inserted element has a key equivalent to the one of an element already in the container, and if so, the element is not inserted, returning an iterator to this existing element
if ( !myMap.insert( std::make_pair( key, value ) ).second )
{
// Element already present...
}
My application merges two std::map instances. If there are no duplicates, the merge completes without intervention. However, if a duplicate is detected, then the method asks whether the new value should be ignored or overwritten. (This query may be answered by a rule table, message box to the user, or some other logic ... it is just an instance of a class derived from a pure virtual class with a bool confirm() const method.)
If the insert fails, and they decide to overwrite the existing entry, I already have an iterator pointing to the correct item to update. Can I use this iterator to update the value directly, or do I have to call operator[] and take the hit of another lookup?
// typedef std::map<Foo, Foo, Compare> Dictionary;
// Dictionary this_dictionary, other_dictionary;
for (Dictionary::const_iterator i = other_dictionary.begin();
i != other_dictionary.end();
++i) {
std::pair<Dictionary::iterator,bool> ret = this_dictionary.insert(*i);
if (!ret.second && confirmer.confirm()) {
// ???
}
}
You need to use Dictionary::iterator instead of Dictionary::const_iterator in the return from insert.
for (Dictionary::const_iterator i = other_dictionary.begin();
i != other_dictionary.end();
++i) {
// Use standard iterator here
std::pair<Dictionary::iterator,bool> ret = this_dictionary.insert(*i);
if (!ret.second && confirmer.confirm()) {
ret.first->second = i->first;
}
}
You can, but you need to use iterator instead of const_iterator.
I have another problem I can't seem to solve..., or find on this site...
I have an object (called DataObject) with a map, declared as follows:
std::map<size_t, DataElement*> dataElements;
Now i have a copy function (used in the copy constructor):
void DataObject::copy(DataObject const &other) {
//here some code to clean up the old data in this object...
//copy all the elements:
size = other.getSize();
for(size_t i = 0; i < size; ++i) {
DataElement* dat = new DataElement(*other.dataElements[i]);
dataElements[i] = dat;
}
}
This doesn't compile, since dataElements[i] is not possible on a const object. How do I make a deep copy of all the elements in the map that is owned by a const object?
I know that the find() function is possible on a const map, but then how do I get to the actual object that I want to copy?
std::map<size_t, DataElement*>::const_iterator it = other.dataElements.begin();
while(it != other.dataElements.end())
{
dataElements[it->first] = new DataElement(*(it->second));
++it;
}
I'm almost positive this should work.
You need to use std::transform. This does a copy whilst also performing a function on each element. In your case a deep copy of the value.
This will therefore do as a transformer:
class DeepCopyMapPointer
{
typedef std::map<size_t, DataElement*> map_type;
typedef map_type::value_type value_type;
public:
value_type operator()( const value_type & other ) const
{
return value_type(other.first, new DataElement(*other.second) );
}
};
void DataObject::copy(DataObject const &other)
{
std::transform(other.dataElements.begin(), other.dataElements.end(),
std::inserter( dataElements, dataElements.end() ), DeepCopyMapPointer() );
}
It's not quite that simple because if you do duplicate an element and your insert fails as a result you will get a leak. You could get round that by writing your own inserter instead of std::inserter... a bit tricky but that's your next exercise.
Since your map just has integer keys from 0 to n - 1, just change your container type to a vector, and your current code should work nicely (you'll need to resize the destination container to make sure there's enough room available).
If you need to use map for some reason (existing API?), as you discovered operator[] has only a non-const version.
Instead use a const_iterator approach (upvoted and taken from #PigBen's answer):
std::map<size_t, DataElement*>::const_iterator it = other.dataElements.begin();
while(it != other.dataElements.end())
{
dataElements[it->first] = new DataElement(*(it->second));
++it;
}
Don't have much time to answer now so this will be brief. There is a copy-constructor for map, but it won't do a deep copy. You want to use iterators (map.begin(), map.end()). *Iter will give you a pair object, so you can do (*iter).first and/or (*iter).second. (Or something like that... It's been a while...)
Ref: http://www.sgi.com/tech/stl/Map.html
for (auto& kv : other.dataElements) {
dataElements[kv.first] = new DataElement(*kv.second);
}
Just one observation :- You are giving direct access to the dataElements. (other.dataElements). Keep dataElements private and then give method like GetDataElement.