简体   繁体   中英

Is there a way to remove a key from a C++ map without deleting the contents?

I have a Class named Shape, and a ShapeStorage Class. ShapeStorage class has a map...

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

and a function...

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

My goal is to be able to have my main class instantiate a ShapeStorage object, store some Shape* in the shapes map. Then later on I want to delete it from my map, but not delete the value itself. I want my main class to still be able to access the value.

I have tried making it, and my pointer still returns correct values, but I'm afraid that since the destructor is being called for Shape when I delete the pointer from my map, so it's just garbage data at that point.

Is there any way around this?

If you're storing pointers, map will not call your destructor. If it's getting called, it's getting called somewhere else.

Try running this example:

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

You should get this:

Shape added
Shape removed from map, now exiting

Your map only holds pointers to Shape s. Removing a pointer from a map has no effect whatsoever on the object it points to, it only destroys the pointer in the map.

Also, your function will perform a lookup by key twice. Once when using operator [] and second time when calling erase () with a key. Here is a better way of doing this:

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;  
}
Shape* shape = shapes[key];  
shapes.erase(key); 

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

This is perfectly fine. You can use shape variable safely.

In fact, it is your responsibility to delete shape . It is not the responsibility of std::map .

std::map不会自动删除它包含的指针。

All STL containers store values - pointers in you case. So the destructor (not deconstructor :) for Shape is not called when you erase the entry.

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

I'm afraid that since the deconstructor is being called for Shape when I delete the pointer from my map,

Above code does not delete the Shape object. It only removes it from the map, which seems to be exactly what you want.

When you call erase on a pointer the destructor is not called, so you're current solution should work fine.

STL has value-semantics rather than reference semantics. So, a copy of your pointer is made on insertion to the map. The copy will die off, but your original will still point to the same memory location that it always did, and the value in that location will still be present until you delete it via the pointer (or until that value goes out of scope if it was stack based and the pointer was set using the & operator).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM