C++ 多重映射清除
这是一个简单的事件系统,我使用多重映射制作;当我使用CEvents::Add(..)方法时,它应该插入并输入到多重映射中。问题是,当我触发这些事件时,多重映射看起来是空的。我肯定我没有调用delete方法[CEvents::Remove]。代码如下:C++ 多重映射清除,c++,multimap,C++,Multimap,这是一个简单的事件系统,我使用多重映射制作;当我使用CEvents::Add(..)方法时,它应该插入并输入到多重映射中。问题是,当我触发这些事件时,多重映射看起来是空的。我肯定我没有调用delete方法[CEvents::Remove]。代码如下: //Code: .. CEvents Ev; Ev.Add("onButtonBReleased",OutputFST); .. // "CEvents.h" class CEvents { public: void
//Code:
..
CEvents Ev;
Ev.Add("onButtonBReleased",OutputFST);
..
// "CEvents.h"
class CEvents
{
public:
void Add ( string EventName, void(*fn)(void));
void Remove ( string EventName, void(*fn)(void));
void Trigger ( string EventName );
//protected:
bool Found;
std::multimap<string,void(*)(void)> EventsMap;
std::multimap<string,void(*)(void)>::iterator EvMapIt;
};
//CEvents.cpp
void CEvents::Add (string EventName, void (*fn)(void))
{
if (!EventsMap.empty())
{
Found = false;
for (EvMapIt = EventsMap.begin(); EvMapIt != EventsMap.end(); EvMapIt++)
{
if ((EvMapIt->first == EventName) && (EvMapIt->second == fn))
{
CTools tools;
tools.ErrorOut("Function already bound to same event... Not registering event");
Found = true;
}
}
if (!Found)
{
EventsMap.insert(std::pair<string,void(*)(void)>(EventName,fn));
std::cout<<"Added, with size "<<(int) EventsMap.size()<<std::endl; //Getting 1
}
}
else
{
EventsMap.insert (std::pair<string,void(*)(void)>(EventName,fn));
std::cout<<"Added, with size "<<(int) EventsMap.size()<<std::endl; //Getting 1
}
}
void CEvents::Trigger (string EventName)
{
std::cout<<"Triggering init"<<std::endl;
std::cout<<(int) EventsMap.size()<<std::endl; //Getting 0
for (EvMapIt = EventsMap.begin(); EvMapIt != EventsMap.end(); EvMapIt++)
{
std::cout<<"Triggering proc"<<std::endl;
if (EvMapIt->first == EventName)
EvMapIt->second();
}
}
//代码:
..
CEEV;
Ev.添加(“OnButtonDeleted”,OutputFST);
..
//“CEvents.h”
类事件
{
公众:
void Add(字符串EventName,void(*fn)(void));
void Remove(字符串EventName,void(*fn)(void));
无效触发器(字符串EventName);
//受保护:
布尔发现;
std::multimap EventsMap;
std::multimap::迭代器EvMapIt;
};
//CEvents.cpp
void CEvents::Add(字符串EventName,void(*fn)(void))
{
如果(!EventsMap.empty())
{
发现=错误;
对于(EvMapIt=EventsMap.begin();EvMapIt!=EventsMap.end();EvMapIt++)
{
如果((EvMapIt->first==EventName)&&(EvMapIt->second==fn))
{
CTools工具;
ErrorOut(“函数已绑定到同一事件…未注册事件”);
发现=真;
}
}
如果(!找到)
{
插入(std::pair(EventName,fn));
std::cout这不是如何使用映射。可以使用映射,这可能比迭代集合中的所有元素更快。如果要确保键是唯一的,则可以使用普通映射,而不是多映射,多映射明确用于将重复键存储为唯一实体
编辑:根据您的注释更新键不应该是唯一的。然后,您应该使用和进行搜索,这比将所有键检查为find
(从内存中)只返回下限值要好。或者,您也可以只迭代一个键的结果(如注释中的标记所示)这将导致同样的结果
只要看一眼您的代码(由于缺少擦除
、清除
或交换
调用),我猜您的问题在于您将元素添加到集合中时,而不是将其“清空”。顺便说一句,为了加快速度,最好在找到项目时中断您的for:
for (EvMapIt = EventsMap.begin(); EvMapIt != EventsMap.end(); EvMapIt++)
{
if ((EvMapIt->first == EventName) && (EvMapIt->second == fn))
{
CTools tools;
tools.ErrorOut("Function already bound to same event... Not registering event");
Found = true;
break;
}
}
编辑:
“插入成员函数返回一个迭代器,该迭代器指向新元素插入多重映射的位置。”(msdn)
为了确保插入正确,请输入插入的返回值。它不应该是代码审阅站点,但我无法控制自己
// "CEvents.h"
class CEvents
{
public:
typedef void (*Callback)(void);
// 1. Don't use `using namespace` in header files
// 2. Pass by const reference to avoid a copy
// 3. Function Pointers are easier to deal with when typedef'd
void Add(std::string const& EventName, Callback fn);
void Remove(std::string const& EventName, Callback fn);
void Trigger(std::string const& EventName);
// Attributes should be `private` or `public`, `protected` is for functions.
// If you read otherwise, consider how this violates encapsulation.
//protected:
private: // cause nobody's touching my stuff lest they break it!
// useless in this class, should be local variables in the routines
// bool Found;
// MapType::iterator EvMapIt;
// typedef make life easier, spelling that out each time is just tiring.
typedef std::multimap<std::string, Callback> MapType;
MapType EventsMap;
};
/“CEvents.h”
类事件
{
公众:
typedef void(*回调)(void);
//1.不要在头文件中使用'using namespace'
//2.传递常量引用以避免复制
//3.使用typedef时,函数指针更容易处理
voidadd(std::stringconst&EventName,回调fn);
void Remove(std::string const&EventName,回调fn);
无效触发器(std::string const和EventName);
//属性应为'private'或'public','protected'用于函数。
/如果你不读,考虑一下这是如何违反封装的。
//受保护:
因为没人碰我的东西,免得他们弄坏了!
//在这个类中无用,应该是例程中的局部变量
//布尔发现;
//MapType::迭代器EvMapIt;
//typedef让生活变得更轻松,每次都把它拼出来是很累的。
typedef std::多映射映射类型;
地图类型事件地图;
};
好的,让我们来看看源文件
//CEvents.cpp
// Whole rewrite to use idiomatic interfaces
void CEvents::Add(std::string const& EventName, Callback fn)
{
// Retrieve the range of callbacks registered for "EventName"
std::pair<MapType::iterator, MapType::iterator> const range =
EventsMap.equal_range(EventName);
// Check that this callback is not already registered.
for (MapType::iterator it = range.first, end = range.second;
it != end; ++it)
{
if (it->second == fn) {
// Are you sure `ErrorOut` should not be a free function
// or at least a `static` function ?
// It feels weird instantiating this class.
CTools tools;
tools.ErrorOut("Function already bound to same event..."
" Not registering event");
// If it is in there, nothing to do, so let's stop.
return;
}
}
// If we are here, then we need to add it.
// Let's give a hint for insertion, while we are at it.
EventsMap.insert(range.second, std::make_pair(EventName, fn));
// the (int) cast was C-like (bah...) and unnecessary anyway
std::cout << "Added, with size " << EventsMap.size() << std::endl;
}
void CEvents::Trigger (std::string const& EventName)
{
std::cout << "Triggering init" << std::endl;
std::cout << EventsMap.size() << std::endl; //Getting 0
// Retrieve the range of callbacks registered for `EventName`
std::pair<MapType::const_iterator, MapType::const_terator> const range =
EventsMap.equal_range(EventName);
// Call each callback in turn
for (MapType::const_iterator it = range.first, end = range.second;
it != end; ++it)
{
it->second();
}
}
//CEvents.cpp
//全部重写以使用惯用接口
void CEvents::Add(std::string const&EventName,回调fn)
{
//检索为“EventName”注册的回调的范围
std::成对常数范围=
EventsMap.equal_范围(EventName);
//检查此回调是否尚未注册。
对于(MapType::iterator it=range.first,end=range.second);
它!=结束;++它)
{
如果(它->秒==fn){
//你确定'ErrorOut'不应该是自由函数吗
//或者至少是一个“静态”函数?
//实例化这个类感觉很奇怪。
CTools工具;
ErrorOut(“函数已绑定到同一事件…”
“未登记事件”);
//如果它在那里,没什么可做的,所以让我们停下来。
返回;
}
}
//如果我们在这里,那么我们需要添加它。
//在插入时,让我们给出一个提示。
EventsMap.insert(range.second,std::make_pair(EventName,fn));
//(int)的演员阵容是C型的(呸…),无论如何都是不必要的
std::coutOk,最后解决了它;供将来参考:
每次声明实例时,它都会重新定义多重映射。
解决方案是创建一个指向该类的全局指针
感谢所有回答的人!键不应该是唯一的,我只是在检查键和值是否同时存在。除此之外,键可以存在多次。@MarwanDessouki,您可以迭代equal\u range
返回的范围,而不是整个地图。@Markransem谢谢您的建议。猜一猜,您正在添加到映射的副本,而不是您用于查找的映射。@BenVoigt您能简单地告诉我如何解决它吗?:-)恐怕错误不在您显示的代码中。如果可以,请尝试使用,并在那里执行一个显示您看到的行为的最小示例,这样您就可以确保包含了查看b所需的代码ug:)@MatthieuM.True,现在测试它->调用类的实例是否会导致它重新定义变量,可能会重置?@MarwanDessouki:#define string std::string
有点笨拙,您可以使用using std::string;
将类型string
带入当前范围。仍然只在源文件中这样做,不是页眉。谢谢,我会的