我正在审查一些代码,我看到的一个常见模式是将对象集合存储为存储对象类的静态成员。
例如,如果我有一类对象:类小部件,则窗口小部件列表将作为静态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;
}
答案 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