在类中使用静态集合来存储类

Use of static collections within a class to store class

本文关键字:集合 存储 静态      更新时间:2023-10-16

我正在检查一些代码,我看到的一个常见模式是将对象集合存储为正在存储的对象类的静态成员。

例如,如果我有一个object类:class widget,那么widget列表将作为静态std::列表存储在widget类中。

要做到这一点,最明显的方法是有一个应用程序级别(全局级别)std::list -然后查找这个应用程序级别列表中的项。

我可以看到静态成员集合的想法对于a的用户来说更方便。还有其他的优点吗?有没有其他类似的选择?a和b方法的优缺点是什么?

下面是代码中的两个替代选项:

file a.hpp:
//Using collection as static member of class idea
class a {
public:
  a();
  ~a();
  class id2a_map;
  static class id2a_map id_map;
  static a* Find(unsigned id);
  unsigned m_id;
};
file a.cpp:
#include <map>
#include "a.hpp"
class a::id2a_map : public std::map<int, a*>
{
};
a::id2a_map a::id_map;
a::a() {
  static unsigned id_cnt = 0;
  ++id_cnt;
  id_map.insert(id_map.end(), id2a_map::value_type(m_id = id_cnt, this));
}
a::~a() {
   id_map.erase(m_id);
}
a* a::Find(unsigned id) {
  id2a_map::iterator i = id_map.find(id);
  return i==id_map.end() ? 0 : i->second;
}

file b.hpp:
// b class - not using static collection
class b {
public:
  b(unsigned id) : m_id(id) { }
  unsigned get_id() const { return m_id; }
private:
  unsigned m_id;
};
file main.cpp to exercise a and b:
#include <iostream>
#include <map>
#include "a.hpp"
#include "b.hpp"
int main() {
  // approach using static map within class
   a obj1;
   a obj2;
   a obj3;
   a obj4;
   a* fnd = a::Find(2);
   std::cout << "object with id 2 " << (fnd ? "" : "not ") << "foundn";
   // application level map
   std::map<unsigned, b*> id2b_map;
   unsigned id = 0;
   b obj5(++id);
   id2b_map.insert(id2b_map.end(), std::make_pair<unsigned, b*>(id, &obj5));
   b obj6(++id);
   id2b_map.insert(id2b_map.end(), std::make_pair<unsigned, b*>(id, &obj6));
   b obj7(++id);
   id2b_map.insert(id2b_map.end(), std::make_pair<unsigned, b*>(id, &obj7));
   b obj8(++id);
   id2b_map.insert(id2b_map.end(), std::make_pair<unsigned, b*>(id, &obj8));
   std::map<unsigned, b*>::iterator i = id2b_map.find(2);
   std::cout << "object with id 2 " << (i == id2b_map.end() ? "not " : "") << "foundn";
   return 0;
}

我可以看到静态成员集合的思想对于a的用户来说更方便。

除了一些简单的情况外,它并不更方便。添加实例的静态映射意味着添加了一个隐藏的依赖项。是否存在不需要此列表的用例?如果你把它作为一个静态私有实例,你将永远拥有它(不管你是否使用它)。

同样,您编写的代码将在这里产生意想不到的结果:

class a::id2a_map : public std::map<int, a*>

std::map不是为继承而写的,这意味着它没有虚析构函数。当类被销毁时,它的析构函数可能不会被调用(依赖于编译器)。

是否有其他类似的替代方案?a和b方法的优缺点是什么?

B方法更好,但没有达到应有的效果。实现将不依赖std::list(最小化依赖总是一个优点),但列表有指针,它不应该。

你能写这样的东西吗?

class a {
public:
  a();
  ~a();
  unsigned m_id; // same as in your example
};
客户机代码:

std::map<unsigned, a> instances; // not static; if you need it somewhere else,
                                 // just pass it in as a parameter
a instance;
instances[a.m_id] = std::move(a);
// use instances.find from here on
代码是直接的,最小的,并且不破坏SRP。

在静态成员的情况下,如果您有静态方法对它们做一些事情,因为编译器在编译时知道所有这些方法将做什么,所以它有更好的机会很好地优化它们。根据编译器的不同,优化的数量也不同。

这是一个有趣的讨论:http://bytes.com/topic/c/answers/617238-static-functions-better-optimized-compilers