简体   繁体   English

正确的方法来销毁具有指针值的地图

[英]Proper way to destroy a map that has pointer values

I am using std::map to map string values to MyType * . 我使用std::map将字符串值映射到MyType * My map declaration looks like this: 我的地图声明如下所示:

map<string, MyType *> *my_map = new map<string, MyType>;

my_map is a private member variable of one of my classes. my_map是我的一个类的私有成员变量。 My problem is that I am unsure of how to destroy the map. 我的问题是我不确定如何破坏地图。 When deleteing the map, I would also like to call delete on all of the MyType * contained in the map. 删除地图时,我还想在地图中包含的所有MyType *上调用delete Here is my current destructor: 这是我目前的析构函数:

my_map->erase(my_map->begin(), my_map->end());
delete my_map;

Will this delete the pointers contained in the map, or do I need to iterate through the map to delete each pointer before calling erase? 这会删除地图中包含的指针,还是需要在调用erase之前迭代地图以删除每个指针?

Pointers merely point. 指针只是指向。 When using raw pointers, you need to know which part of your app owns the resources that the pointers point to. 使用原始指针时,您需要知道应用程序的哪个部分拥有指针所指向的资源。 If they are owned by the map, you will need to iterate over the map and call delete on each pointer before the map is destroyed. 如果它们由地图拥有,则需要迭代地图并在销毁地图之前在每个指针上调用delete。 But if the map just holds pointers to objects that are owned by other parts of your code, you don't need to do anything. 但是,如果地图只保存指向代码其他部分所拥有的对象的指针,则无需执行任何操作。

A safer solution is to use shared_ptr to manage object lifetime, which will ensure that the object gets deleted properly when the last shared_ptr is destroyed. 更安全的解决方案是使用shared_ptr来管理对象生存期,这将确保在销毁最后一个shared_ptr时正确删除对象。 You can store shared_ptrs inside the map and if no other shared_ptr instances reference the objects within the map, the objects will be destroyed when the map is destroyed, as desired. 您可以将shared_ptrs存储在地图中,如果没有其他shared_ptr实例引用地图中的对象,则根据需要在销毁地图时将销毁对象。

If you use smart pointers instead of raw pointers, everything will be cleaned up for you automatically. 如果您使用智能指针而不是原始指针,则会自动为您清理所有内容。

// header:
using MapType = std::map<std::string, std::shared_ptr<MyType>>;
shared_ptr<MapType> my_map;

// usage:
my_map.emplace("foo", std::make_shared<MyType>());

// destructor:
MyClass::~MyClass()
{
    // nothing!
}

Will this delete the pointers contained in the map [...]? 这会删除地图中包含的指针[...]吗?

No, given the code you have provided, you will leak every member of the map. 不,鉴于您提供的代码,您将泄漏地图的每个成员。

As a rule, for every new there must be a matching delete . 通常,对于每个new ,必须有匹配的delete You have a delete for the map, but none for the elements within. 您有一个delete地图,但没有delete其中的元素。

The most correct solution to this problem is to not use dynamic allocation at all. 解决此问题的最正确方法是根本不使用动态分配。 Just store MyType s directory, if possible: 如果可能的话,只需存储MyType的目录:

map<string, MyType>

... and instead of dynamically allocating the map itself, store that automatically: ...而不是动态分配map本身,自动存储:

map<string,MyType> my_map;

If automatic storage duration is not possible for some reason, then use a smart pointer for the dynamic allocations. 如果由于某种原因无法自动存储持续时间,则使用智能指针进行动态分配。 Given a C++11 compiler, use unique_ptr (or, rarely, shared_ptr or even weak_ptr ) for the elements in the map : 给定C ++ 11编译器,对map的元素使用unique_ptr (或很少, shared_ptr甚至weak_ptr ):

map<string, unique_ptr<MyType>> my_map;

(Given a C++03 compiler, use the Boost equivalents thereof.) Then when my_map is destroyed, all the elements will be delete d. (给定一个C ++ 03编译器,使用它的Boost等价物。)然后当my_map被销毁时,所有元素都将被delete

Baring all of this, if you are in a situation where none of the above will work for you (I would by highly suspect), then you will need to iterate the map youself: 所有这一切,如果您处于上述任何一种都不适合您的情况(我会非常怀疑),那么您需要自己迭代地图:

struct deleter
{
  template <typename T> operator() (const T& rhs) const
  { 
    delete rhs.second;
  }
};

for_each (my_map->begin(), my_map->end(), deleter());

In C++11, this could be made a lambda, something along the line of: 在C ++ 11中,这可以成为一个lambda,类似于:

for_each (my_map->begin(), my_map->end(), [](auto item) -> void
{
  delete item.second;
});

In modern C++, just make your life easier and use pointers only if strictly required. 在现代C ++中, 只有在严格要求时才能让您的生活更轻松并使用指针。

You started with this code: 您从这段代码开始:

 map<string, MyType *> *my_map = new map<string, MyType>; 

The first thing you can do is to consider using a std::map instance as data member, instead of a pointer to it. 您可以做的第一件事是考虑使用std::map实例作为数据成员,而不是指向它的指针

Then, if MyType is not super-expensive to copy and its instances are only owned by the map, just consider a simple map from string to MyType (instead of MyType* ): 然后,如果复制MyType并不是非常昂贵且其实例仅由地图拥有,那么只需考虑从stringMyType (而不是MyType* )的简单map

// my_map data member - no pointers --> automatically deleted in class destructor
map<string, MyType> my_map;

If you really need a map containing pointers, consider using smart pointers , like std::shared_ptr (available in C++11/14) for shared ownership, or std::unique_ptr for unique non-shared ownership. 如果你真的需要一个包含指针的映射,可以考虑使用智能指针 ,如std::shared_ptr (在C ++ std::shared_ptr可用)用于共享所有权,或者std::unique_ptr用于唯一的非共享所有权。
(If you target C++98/03, an option is to use boost::shared_ptr . Since there is no move semantics, you can't have unique_ptr , which is heavily based on the move semantics feature.) (如果你的目标是C ++ 98/03,一个选项是使用boost::shared_ptr 。由于没有移动语义,你不能拥有unique_ptr ,这很大程度上基于移动语义特性。)
eg: 例如:

// Map containing _smart_ pointers 
//     --> default destructor is fine (no need for custom delete code)
map<string, shared_ptr<MyType>> my_map;

As you can see, using value semantics (instead of raw pointers), or smart pointers , you can simplify your code and use the automatic destruction provided by C++. 如您所见,使用值语义 (而不是原始指针)或智能指针 ,您可以简化代码并使用C ++提供的自动销毁

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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