Как (глубоко) скопировать карту из константного объекта - PullRequest
3 голосов
/ 27 октября 2010

У меня есть еще одна проблема, которую я не могу решить ... или найти на этом сайте ...

У меня есть объект (называемый DataObject) с картой, объявленной следующим образом:

std::map<size_t, DataElement*> dataElements;

Теперь у меня есть функция копирования (используется в конструкторе копирования):

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;
    }

}

Это не компилируется, поскольку dataElements [i] невозможен для объекта const.Как сделать полную копию всех элементов на карте, принадлежащих константному объекту?

Я знаю, что функция find () возможна на константной карте, но тогда как мне добраться дофактический объект, который я хочу скопировать?

Ответы [ 6 ]

8 голосов
/ 27 октября 2010
std::map<size_t, DataElement*>::const_iterator it = other.dataElements.begin();
while(it != other.dataElements.end())
{
    dataElements[it->first] = new DataElement(*(it->second));
    ++it;
}

Я почти уверен, что это должно сработать.

1 голос
/ 27 октября 2010

Поскольку ваша карта содержит целочисленные ключи от 0 до n - 1, просто измените тип контейнера на вектор, и ваш текущий код должен работать хорошо (вам нужно изменить размер контейнера назначения, чтобы убедиться, что достаточнокомната доступна).

Если вам нужно по какой-то причине использовать map (существующий API?), как вы обнаружили, operator[] имеет только неконстантную версию.

Вместо этого используйтеconst_iterator подход (голосование взято и взято из ответа @ PigBen):

std::map<size_t, DataElement*>::const_iterator it = other.dataElements.begin();
while(it != other.dataElements.end())
{
    dataElements[it->first] = new DataElement(*(it->second));
    ++it;
}
1 голос
/ 27 октября 2010

Вам необходимо использовать std :: transform. Это делает копию, одновременно выполняя функцию для каждого элемента. В вашем случае глубокая копия значения.

Таким образом, это будет действовать как трансформатор:

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() );
}

Это не так просто, потому что, если вы дублируете элемент, и ваша вставка завершается неудачно, вы получите утечку. Вы можете обойти это, написав свой собственный вставщик вместо std :: insertter ... немного хитро, но это ваше следующее упражнение.

0 голосов
/ 05 февраля 2019
for (auto& kv : other.dataElements) {
            dataElements[kv.first] = new DataElement(*kv.second);
        }
0 голосов
/ 27 октября 2010

Только одно наблюдение: - Вы даете прямой доступ к элементам данных.(other.dataElements).Оставьте dataElements закрытыми, а затем предоставьте метод, подобный GetDataElement.

0 голосов
/ 27 октября 2010

У меня не так много времени, чтобы ответить, так что это будет кратко.Существует конструктор копирования для карты, но он не будет делать глубокую копию.Вы хотите использовать итераторы (map.begin (), map.end ()).* Iter даст вам пару объектов, так что вы можете сделать (* iter) .first и / или (* iter) .second.(Или что-то в этом роде ... Это было давно ...)

Ссылка: http://www.sgi.com/tech/stl/Map.html

...