C++ - 使用好友关键字来提高效率?

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关键字?

Cas*_*Cow 5

你的设计有很多问题.您正在递归,因为邮件中有文件夹和文件夹包含邮件.您需要比较文件夹和消息,并且您没有所有权的概念.

您需要暂时忘记代码并查看数据建模.

你有一组文件夹.我假设每个人都有一个文件夹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)

代替FolderMessage在最后两个地图中,您可以使用智能指针类型来启用放置和检索.我会简单易用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的头定义,反之亦然.因此,您不会遇到依赖性问题.经理需要包含所有类类型.

  • +1描述得很好.使用`std :: vector <Folder>`/`std :: vector <Message`,id为`vector`索引是另一个更简单/更快的选项,如果它们永远不会被删除,直到整个消息/文件夹数据完成. (3认同)