Reputation: 263
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?
Upvotes: 7
Views: 13166
Reputation: 1158
for (auto& kv : other.dataElements) {
dataElements[kv.first] = new DataElement(*kv.second);
}
Upvotes: 0
Reputation: 96241
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;
}
Upvotes: 1
Reputation: 31435
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.
Upvotes: 2
Reputation: 3247
Just one observation :- You are giving direct access to the dataElements. (other.dataElements). Keep dataElements private and then give method like GetDataElement.
Upvotes: -1
Reputation: 103693
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.
Upvotes: 10
Reputation: 8418
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
Upvotes: 0