给定具有n
条目的地图的主副本,复制起来很昂贵。我需要一次更改一个地图中的条目值,并在新地图上执行一些操作。我想知道是否有一种有效的方法来实现它,而无需复制主地图n
次。
在下面的代码中,XYZ
是一个复制成本很高的类,我需要执行的操作不是必需的总和。我选择总结是为了说明目的。
class BigMap
{
private:
std::map<int, XYZ> m;
public
std::map<int, XYZ>::const_iterator begin() const
{
return m.begin();
}
std::map<int, XYZ>::iterator begin()
{
return m.begin();
}
std::map<int, XYZ>::const_iterator end() const
{
return m.end();
}
std::map<int, XYZ>::iterator end()
{
return m.end();
}
void PopulateBigMapWithLotsOfData(int size)
{
for (int i = 0; i < size; ++i)
{
m[i] = XYZ();
}
}
};
double Aggregate(const BigMap& bm)
{
double result = 0.0;
for (const auto& entry : bm)
{
result += entry.second.Value();
}
}
int main()
{
BigMap bm;
bm.PopulateBigMapWithLotsOfData(1000);
double result = 0.0;
// This for loop will be in a multi-threaded environment.
// Thus I do need a shallow copy of bm in each thread.
for (int i = 0; i < 1000; ++i)
{
BigMap newBm(bm); // An expensive copy
newBm[i].ChangeValue(); // Modify single entry
result += Aggregate(newBm); // Perform some operation on the new map
}
return result;
}
我正在考虑类似下面这样的内容,但我被困在迭代器部分,因为Aggregate
函数需要能够使用begin
和{{循环遍历地图的所有条目1}}迭代器被定义。
end
基本上,原始地图中具有特定键的条目永远不会被访问,因为它被class BigMap
{
public:
XYZ& Find(int index)
{
return ptr->Find(index);
}
const XYZ& Find(int index) const
{
return ptr->Find(index);
}
private:
AbstractBigMap* ptr; // Pointer so that I can apply virtual function.
};
class AbstractBigMap
{
public:
virtual XYZ& Find(int index);
virtual const XYZ& Find(int index) const;
}
class OriginalBigMap : public AbstractBigMap
{
public:
XYZ& Find(int index)
{
return m.find(index)->second;
}
const XYZ& Find(int index) const
{
return m.find(index)->second;
}
private:
std::map<int, XYZ> m;
};
class ModifiedBigMap : public AbstractBigMap
{
public:
// Reference on the original map to avoid copying.
ModifiedBigMap(const OriginalBigMap& original, int index)
: _original(original), _index(index)
{
// Copy single entry from the original map so we can modify it
_m[index] = _original.m.find(index)->second;
}
XYZ& Find(int index)
{
assert(index == _index);
return _m[index].second;
}
const XYZ& Find(int index) const
{
if (index == _index)
return _m[index].second;
else
return _original.Find(index);
}
private:
const OriginalBigMap& _original;
std::map<int, XYZ> _m;
int _index;
};
中的单个条目替换。
编辑: 我应该指出for循环实际上是在一个多线程环境中,因此我不能简单地复制该条目并在操作后替换它。
答案 0 :(得分:1)
您可以在调用函数时替换地图中某个位置的值:
#include <iostream>
#include <algorithm>
template <typename Map>
struct Invoke
{
using value_type = typename Map::mapped_type;
using const_iterator = typename Map::const_iterator;
const_iterator position;
value_type replace_value;
Invoke(const_iterator position, value_type replace_value)
: position(position), replace_value(replace_value)
{}
template <typename Function>
value_type operator () (const Map& map, const Function& function) const
{
value_type result = value_type();
for(auto pos = map.begin(); pos != map.end(); ++pos) {
if(pos == position) result = function(result, replace_value);
else result = function(result, pos->second);
}
return result;
}
};
int main(int argc, const char *argv[])
{
using map_type = std::map<int, int>;
map_type map = { {0, 0}, {1, 1}, {2, 2} };
for(auto pos = map.begin(); pos != map.end(); ++pos) {
Invoke<map_type> invoke(pos, -1);
std::cout << invoke(map, std::plus<int>()) << '\n';
}
}
或者,您可以使用自定义迭代器:
#include <iostream>
#include <algorithm>
template <typename Iterator>
struct ReplaceIterator
{
public:
using iterator = Iterator;
using iterator_category = std::forward_iterator_tag ;
using difference_type = typename iterator::difference_type;
using value_type = typename iterator::value_type;
using reference = typename iterator::reference;
using pointer = typename iterator::pointer;
// Construction
// ============
public:
explicit ReplaceIterator(iterator position, iterator replace_position, value_type replace_value)
: m_position(position), m_replace_position(replace_position), m_replace_value(replace_value)
{}
// Element Access
// ==============
public:
const iterator& position() const { return m_position; }
reference& value() const {
return (m_position == m_replace_position)
? m_replace_value
: *m_position;
}
// Iterator
// ========
public:
reference operator * () const { return value(); }
pointer operator -> () const { return &value(); }
ReplaceIterator& operator ++ () {
++m_position;
return *this;
}
ReplaceIterator operator ++ (int) {
ReplaceIterator tmp(*this);
++m_position;
return tmp;
}
// Compare
// =======
public:
friend bool operator == (const ReplaceIterator& a, const ReplaceIterator& b) {
return a.m_position == b.m_position;
}
friend bool operator == (const iterator& a, const ReplaceIterator& b) {
return a == b.m_position;
}
friend bool operator == (const ReplaceIterator& a, const iterator& b) {
return a.m_position == b;
}
friend bool operator != (const ReplaceIterator& a, const ReplaceIterator& b) {
return a.m_position != b.m_position;
}
friend bool operator != (const iterator& a, const ReplaceIterator& b) {
return a != b.m_position;
}
friend bool operator != (const ReplaceIterator& a, const iterator& b) {
return a.m_position != b;
}
private:
iterator m_position;
iterator m_replace_position;
mutable value_type m_replace_value;
};
int main(int argc, const char *argv[])
{
using map_type = std::map<int, int>;
map_type map = { {0, 0}, {1, 1}, {2, 2} };
for(auto pos0 = map.begin(); pos0 != map.end(); ++pos0) {
int result = 0;
ReplaceIterator<map_type::const_iterator> pos1(map.begin(), pos0, {0, -1});
for( ; pos1 != map.end(); ++pos1)
result += pos1->second;
std::cout << result << '\n';
}
}
两者都会打印:
2
1
0