Есть ли способ удалить ключ из карты C ++ без удаления содержимого? - PullRequest
4 голосов
/ 01 декабря 2011

У меня есть класс с именем Shape и класс ShapeStorage. Класс ShapeStorage имеет карту ...

std::map<int, Shape*> shapes;

и функция ...

Shape * ReturnShapePointer(int key)  
{  
    Shape* shape = shapes[key];  
    shapes.erase(key);  
    return shape;  
}

Моя цель - сделать так, чтобы мой основной класс создал экземпляр объекта ShapeStorage, сохранил немного Shape * на карте фигур. Затем я хочу удалить его с карты, но не удалять само значение. Я хочу, чтобы мой основной класс все еще мог получить доступ к значению.

Я попытался сделать это, и мой указатель по-прежнему возвращает правильные значения, но я боюсь, что, поскольку деструктор вызывается для Shape, когда я удаляю указатель из моей карты, так что в этот момент это просто мусорные данные.

Есть ли способ обойти это?

Ответы [ 7 ]

4 голосов
/ 01 декабря 2011

Если вы храните указатели, map не вызовет ваш деструктор.Если вызывается, вызывается куда-то еще.

Попробуйте выполнить этот пример:

#include <iostream>
#include <map>

class Shape {
public:
    ~Shape() {
        std::cout << "Shape deleted" << std::endl;
    }
};

int main(int argc, char *argv[]) {
    std::map<int, Shape *> shapes;
    shapes[1] = new Shape();
    std::cout << "Shape added" << std::endl;
    shapes.erase(1);
    std::cout << "Shape removed from map, now exiting" << std::endl;
}

Вы должны получить это:

Shape added
Shape removed from map, now exiting
3 голосов
/ 01 декабря 2011

Ваша карта содержит только указатели на Shape с. Удаление указателя с карты никак не влияет на объект, на который он указывает, оно только уничтожает указатель на карте.

Кроме того, ваша функция выполнит поиск по клавише дважды. Один раз при использовании operator [] и второй раз при вызове erase () с ключом. Вот лучший способ сделать это:

Shape *ReturnShapePointer (int key)  
{  
    Shape *shape;
    std::map<int, Shape*>::iterator it = shapes.find (key);

    if (it != shapes.end ())
    {
        shape = it->second;
        shapes.erase (it);
    }
    else
    {
        shape = NULL;
    }

    return shape;  
}
1 голос
/ 01 декабря 2011
Shape* shape = shapes[key];  
shapes.erase(key); 

//you can use shape here, without any problem!

Это прекрасно. Вы можете безопасно использовать переменную shape.

На самом деле, это ваша ответственность перед delete shape. Это не ответственность std::map.

0 голосов
/ 01 декабря 2011

Когда вы вызываете erase для указателя, деструктор не вызывается, поэтому текущее решение должно работать нормально.

STL имеет семантику значений, а не эталонную семантику.Итак, копия вашего указателя сделана при вставке на карту.Копия умрет, но ваш оригинал все равно будет указывать на ту же область памяти, что и всегда, и значение в этом месте будет присутствовать до тех пор, пока вы не удалите его с помощью указателя (или пока это значение не выйдет из области действия, еслибыл основан на стеке, и указатель был установлен с помощью оператора &).

0 голосов
/ 01 декабря 2011
Shape * ReturnShapePointer(int key)  
{  
    Shape* shape = shapes[key];  
    shapes.erase(key);  
    return shape;  
}

Боюсь, что так как деконструктор вызывается для Shape, когда я удаляю указатель с моей карты,

Приведенный выше код не удаляет объект Shape. Он удаляет его только с карты, которая, кажется, именно то, что вы хотите.

0 голосов
/ 01 декабря 2011

Все контейнеры STL хранят значения - указатели в вашем случае. Таким образом, деструктор (не деконструктор :) для Shape не вызывается при удалении записи.

0 голосов
/ 01 декабря 2011

std::map не удалит указатели, которые он содержит автоматически.

...