我不认为您的问题需要自定义删除器,我认为您遇到问题主要是因为您进行双重簿记。
您有一张地图和一个包含相同信息的矢量,即您世界中的一组动物。我建议你只保留地图。
您需要的是一种简单的方法来迭代地图中的所有动物,因为您可以使用自定义迭代器。这个例子向你展示了如何实现这样的语法:
int main()
{
world_t world;
for (const auto& animal : world.animals())
{
std::cout << animal << std::endl;
}
}
完整的源代码:
(PS。我仍在仔细检查自定义迭代器的完全正确性,
我不经常写它们,但对于这个例子它有效)
// https://stackoverflow.com/questions/69243916/deleting-shared-ptrs-from-unordered-map-when-deleting-shared-ptr-from-vector-s
#include <algorithm>
#include <map>
#include <string>
#include <iostream>
#include <vector>
//=================================================================================================
// map_value_iterator.h
//-------------------------------------------------------------------------------------------------
// implementation of a custom iterator over std::map that returns the values
namespace impl
{
template<typename key_t, typename value_t>
struct const_map_value_iterator_t
{
using iterator_category = std::forward_iterator_tag;
using value_type = value_t;
using difference_type = std::ptrdiff_t;
using pointer = const value_t*; // <== not completely sure this is correct, todo check
using reference = const value_t&;
// the underlying map iterator type
using underlying_iterator_t = typename std::map<key_t, value_t>::const_iterator;
const_map_value_iterator_t() = default;
explicit const_map_value_iterator_t(const underlying_iterator_t& it) :
m_map_iterator{ it }
{
}
const_map_value_iterator_t(const const_map_value_iterator_t& rhs) :
m_map_iterator{ rhs.m_map_iterator }
{
}
const_map_value_iterator_t& operator=(const const_map_value_iterator_t& rhs)
{
m_map_iterator = rhs.m_map_iterator;
}
reference operator*() const
{
return (m_map_iterator->second);
}
pointer operator->() const
{
return &(m_map_iterator->second);
}
const_map_value_iterator_t& operator++()
{
++m_map_iterator;
return *this;
}
const_map_value_iterator_t& operator++(int)
{
++m_map_iterator;
return *this;
}
const_map_value_iterator_t& operator--()
{
--m_map_iterator;
return *this;
}
const_map_value_iterator_t& operator--(int)
{
--m_map_iterator;
return *this;
}
bool operator==(const const_map_value_iterator_t& rhs)
{
return m_map_iterator == rhs.m_map_iterator;
}
bool operator!=(const const_map_value_iterator_t& rhs)
{
return m_map_iterator != rhs.m_map_iterator;
}
private:
underlying_iterator_t m_map_iterator;
};
} /* namespace impl */
//-------------------------------------------------------------------------------------------------
// struct to initialize iterator based on a map
// and to provide a nice grouping of begin/end
// so both can be returned by one getter.
template<typename key_t, typename value_t>
struct map_values_iterator_t
{
explicit map_values_iterator_t(const std::map<key_t, value_t>& map) :
m_begin{ map.begin() },
m_end{ map.end() }
{
}
const auto& begin() const
{
return m_begin;
};
const auto& end() const
{
return m_end;
};
private:
impl::const_map_value_iterator_t<key_t, value_t> m_begin;
impl::const_map_value_iterator_t<key_t, value_t> m_end;
};
//=================================================================================================
// main.cpp
// inline example
struct animal_t
{
animal_t(std::string n, std::size_t v) :
name{ n },
vigor{ v }
{
}
// Sort orde by increasing vigor
static bool order_by_vigor(const animal_t* lhs, const animal_t* rhs)
{
return lhs->vigor > rhs->vigor;
}
std::string name;
std::size_t vigor;
};
class world_t
{
public:
// return the iterator over values in the map
auto animals()
{
return map_values_iterator_t{ m_map };
}
auto animals(bool (*sort_fn)(const animal_t* lhs, const animal_t* rhs))
{
// if your collection of animals is likely to change
// then returning a sorted copy is probably more safe
// (remove the pointer)
// I'd rather would have used references, but they can't be sorted
std::vector<const animal_t*> sorted_animals;
for (const auto& animal : animals())
{
sorted_animals.push_back(&animal);
}
std::sort(sorted_animals.begin(), sorted_animals.end(), sort_fn);
return sorted_animals;
}
private:
std::map<int, animal_t> m_map{ {1,{"bear",9}}, {3,{"cat",2}}, {5,{"dog",4}} };
};
//-------------------------------------------------------------------------------------------------
int main()
{
world_t world;
for (const auto& animal : world.animals(animal_t::order_by_vigor))
{
std::cout << "animal '" << animal->name << "' has vigor '" << animal->vigor << "'" << std::endl;
}
}