Toc*_*cio 2 c++ performance friend
例如,我有这两个类(来自C++ Primer的练习):
class Message{
set<Folder> folders;
public:
void addFolder(Folder f);
}
class Folder{
set<Message> messages;
public:
void addMessage(Message m);
}
Run Code Online (Sandbox Code Playgroud)
方法addFolder(等于addMessage)是这样的:
void addFolder(Folder f){
folders.push_back(f);
f.addMessage(this);
}
void addMessage(Message m){
messages.push_back(m);
m.addFolder(this);
}
Run Code Online (Sandbox Code Playgroud)
问题是这样我将对这两个方法进行无限递归调用(文件夹添加消息,而不是消息添加文件夹并要求文件夹添加消息等).
我有两个解决方案:
1.在每个返回bool的类中有一个公共成员,该值表示给定的消息/文件夹是否在对象的集合中:
void addFolder(Folder f){
folders.push_back(f);
if(!f.search(this)){
f.addMessage(this);
}
}
void addMessage(Message m){
messages.push_back(m);
if(!m.search(this)){
m.addFolder(this);
}
}
Run Code Online (Sandbox Code Playgroud)
这应该工作,但每次我必须控制该设置两次.
另一个解决方案是在每个类中都有一个私有成员,只添加文件夹/消息而不要求另一个添加它.然后把它交给班级朋友.
class Message{
friend class Folder;
set<Folder> folders;
public:
void addFolder(Folder f);
private:
void insertFolder(Folder f){ folders.push_back(f);}
}
class Folder{
friend class Message;
set<Message> messages;
public:
void addMessage(Message m);
private:
void insertMessage(Message m){ messages.push_back(m);}
}
Run Code Online (Sandbox Code Playgroud)
addMessage和addFolder方法将是:
void addFolder(Folder f){
folders.push_back(f);
f.insertMessage(this);
}
void addMessage(Message m){
messages.push_back(m);
m.insertFolder(this);
}
Run Code Online (Sandbox Code Playgroud)
这样就不会有递归调用,而且性能会更高.
在这种情况下,使用朋友提高效率是好的吗?或者最好使用效率较低的方式(如搜索方式?)而不使用friend关键字?
你的设计有很多问题.您正在递归,因为邮件中有文件夹和文件夹包含邮件.您需要比较文件夹和消息,并且您没有所有权的概念.
您需要暂时忘记代码并查看数据建模.
你有一组文件夹.我假设每个人都有一个文件夹ID.你有一组消息.每个人都有一个消息ID.
文件夹和邮件之间存在多对多关系.
给定一个消息ID,您应该能够看到它包含的所有文件夹.给定文件夹ID,您应该能够看到它包含的所有消息.
我假设"文件夹有消息",但实际上它只是一个多对多的关系.您可以使用两个multimaps来存储关系.
std::multimap< FolderId, MessageId >;
std::multimap< MessageId, FolderId >;
Run Code Online (Sandbox Code Playgroud)
您还需要常规地图
std::map< FolderId, Folder >;
std::map< MessageId, Message >;
Run Code Online (Sandbox Code Playgroud)
代替Folder或Message在最后两个地图中,您可以使用智能指针类型来启用放置和检索.我会简单易用shared_ptr.
您也可以在每个Folder/Message对象中包含一个集合,而不是多重映射.这只是从Id到Id的映射.然后,您将引用"管理器",即用于检索基础对象的主要映射.
所以我们可以
class Message
{
std::set< FolderId > folderIds; // folders I am in
// implement construction and access functions etc.
};
typedef std::shared_ptr< Message > MessagePtr;
class Folder
{
std::set< MessageId > messageIds; // messages in this folder
};
typedef std::shared_ptr< Folder > FolderPtr;
Run Code Online (Sandbox Code Playgroud)
把大地图放到某种经理身上
class MessageFolderManager
{
std::map< FolderId, FolderPtr > folders
std::map< MessageId, MessagePtr > messages;
};
Run Code Online (Sandbox Code Playgroud)
请注意,对于依赖项,Folder和Message可能只需要知道其他类型的ID,而不是其他类型本身.所以在Folder.h中你只包含MessageId的头定义,反之亦然.因此,您不会遇到依赖性问题.经理需要包含所有类类型.