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

标签 c++ performance friend

例如,我有这两个类(class)(来自 C++ Primer 的练习):

class Message{
   set<Folder> folders;
public:
   void addFolder(Folder f);
}

class Folder{
   set<Message> messages;
public:
   void addMessage(Message m);
}

addFolder 方法(等于 addMessage)是这样的:

void addFolder(Folder f){
    folders.push_back(f);
    f.addMessage(this);
}

void addMessage(Message m){
    messages.push_back(m);
    m.addFolder(this);
}

问题是,这样我将对这两个方法进行无限递归调用(文件夹添加消息,消息添加文件夹并要求文件夹添加消息等..)。

我想到了两个解决方案:

1.在每个类中都有一个返回 bool 值的公共(public)成员,该值指示给定的消息/文件夹是否在对象集中:

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);
    }
}

这应该可行,但每次我都必须控制该设置两次。

另一个解决方案是在每个类中都有一个私有(private)成员,该成员仅添加文件夹/消息而不要求其他成员添加它。然后把这个送给类的 friend 。

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);}
}

addMessage 和 addFolder 方法将是:

void addFolder(Folder f){
    folders.push_back(f);
    f.insertMessage(this);
}

void addMessage(Message m){
    messages.push_back(m);
    m.insertFolder(this);
}

这样就不会出现递归调用,而且性能会更高。

像这种情况,用friend来提高效率可以吗?或者最好使用性能较差的方式(例如搜索方式?)而不使用friend关键字?

最佳答案

你的设计有很多错误。您正在递归,因为消息有文件夹,文件夹有消息。您需要比较文件夹和邮件,并且没有所有权的概念。

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

您有一组文件夹。我假设每个文件夹都有一个文件夹 ID。 您有一组消息。每一条消息都有一个消息 ID。

文件夹和消息之间存在多对多关系。

给定一个消息 ID,您应该能够看到它包含的所有文件夹。 给定一个文件夹 ID,您应该能够看到它包含的所有消息。

我假设“文件夹有消息”,但实际上它只是一种多对多关系。您可以使用两个多重映射来存储关系。

std::multimap< FolderId, MessageId >;
std::multimap< MessageId, FolderId >;

您还需要常规 map

std::map< FolderId, Folder >;
std::map< MessageId, Message >;

您可以使用支持放置和检索的智能指针类型来代替最后两个映射中的FolderMessage。我会简单地使用 shared_ptr

除了多重映射之外,您还可以在每个文件夹/消息对象中包含一个集合。这只是一个从 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;

将大 map 放入某种管理器中

class MessageFolderManager
{
    std::map< FolderId, FolderPtr > folders
    std::map< MessageId, MessagePtr > messages;
};

请注意,对于依赖项,文件夹和消息可能只需要了解其他类型的 Id,而不是其他类型本身。因此,在Folder.h 中,您只需包含MessageId 的 header 定义,反之亦然。因此你不会遇到依赖性问题。管理器需要包含所有类类型。

关于C++ - 使用friend关键字来提高效率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25200385/

相关文章:

c++ - 不使用标准函数反转字符串

html - 多尺寸的 favicon .ico 文件会影响网页加载速度吗?

javascript - 在javascript中从数组中获取随机项的最佳方法

c++ - 如何将全局范围函数声明为命名空间类的 friend ?

c++ - 为什么一定要用友元功能

c++ - 如何实现 STL 风格的迭代器并避免常见的陷阱?

c++ - Rcpp 编译属性不可调用

c++ - 位域,为什么特定于实现?

c# - 列表的性能问题

C++如何将关键字 'friend'与来自两个类的成员函数一起使用相互包含