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

时间:2014-03-20 14:54:55

标签: c++ design-patterns collections

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

例如,如果我有一类对象:类小部件,则窗口小部件列表将作为静态std :: list存储在窗口小部件类中。

显而易见的方法是拥有一个应用程序级别(全局级别)std :: list - 然后找到一个项目查找此应用程序级别列表。

我可以看到静态成员集合的想法对于用户来说更方便。还有其他优点吗?还有其他替代方案也应该被认为是类似的吗? 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 ") << "found\n";

   // 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 " : "") << "found\n";
   return 0;
}

2 个答案:

答案 0 :(得分:1)

  

我可以看到静态成员集合的想法对于。

的用户来说更方便

除了简单的情况外,它不是更方便。添加静态实例映射意味着您添加了隐藏的依赖项。当您不需要此列表时是否有任何用例?如果将它作为静态私有实例放置,您将始终拥有它(无论您是否使用它)。

此外,您编写的代码在此处会产生意外结果:

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。

答案 1 :(得分:0)

对于静态成员,如果你有静态方法对它们做一些事情,因为编译器知道这些方法在编译时会做什么,所以它有更好的机会对它们进行优化。根据编译器的不同,优化量会有所不同。

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