C++多实例模式的模板化类实现
我使用 C++ 中的模板类实现了 multiton 模式。
#ifndef MULTITON_H
#define MULTITON_H
#include <map>
template <typename Key, typename T> class Multiton
{
public:
static void destroy()
{
for (typename std::map<Key, T*>::iterator it = instances.begin(); it != instances.end(); ++it) {
delete (*it).second;
}
}
static T& getRef(const Key& key)
{
typename std::map<Key, T*>::iterator it = instances.find(key);
if (it != instances.end()) {
return *(T*)(it->second);
}
T* instance = new T;
instances[key] = instance;
return *instance;
}
static T* getPtr(const Key& key)
{
typename std::map<Key, T*>::iterator it = instances.find(key);
if (it != instances.end()) {
return (T*)(it->second);
}
T* instance = new T;
instances[key] = instance;
return instance;
}
protected:
Multiton() {}
virtual ~Multiton() {}
private:
Multiton(const Multiton&) {}
Multiton& operator= (const Multiton&) { return *this; }
static std::map<Key, T*> instances;
};
template <typename Key, typename T> std::map<Key, T*> Multiton<Key, T>::instances;
#endif
使用:
class Foo : public Multiton<std::string, Foo> {};
Foo& foo1 = Foo::getRef("foobar");
Foo* foo2 = Foo::getPtr("foobar");
Foo::destroy();
有什么改进建议吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
1)个人喜好,但我会颠倒模板参数的顺序并将密钥默认为 std::string (如果这是您最常使用的)
那么您可以这样做:
我认为这更好。
2)此外,如果您从不向 Multitron 传递指针/引用(这不会违反模式),您不应该在类中需要虚拟析构函数。
3) 如果您为 T* 使用更智能的容器,则可以避免调用 Foo::destroy()。 的东西> 会在静态实例被销毁时销毁所有对象。 (尽管如果你关心破坏的顺序,那么你需要一些更聪明的东西 - 你可以从现有的单例解决方案中调整一些东西,例如phoenix单例等)
类似于 std::map
4)你可以将迭代器更改为const_iterators。
5) destroy 应该清除映射,以防止调用 destroy 后意外访问无效内存。或者,如果您想防止这种情况发生,您应该抛出异常。
6)如果你不使用多态 T 那么你可以使用 std::map 并且你的代码看起来像这样......
这就是我现在能想到的。
1) Personal preference, but I'd reverse the order of the template parameters and default the Key to std::string (if that's what you'll use most)
Then you can do this:
Which I think is nicer.
2) Also if you're never passing pointers/references to Multitron (which wouldn't kind of violate the patter) you shouldn't need a virtual destructor in the class.
3) If you used a smarter container for your T*s you could avoid having to call Foo::destroy().
Something like
std::map<Key,boost::shared_ptr<T> >
would destroy all the objects when the static instance was destroyed. (Although if you cared about order of destruction, then you'd need something cleverer - you could adapt somethign from existing singleton solutions such as phoenix singletons etc)4) You could change your iterators to const_iterators.
5) destroy should probably clear the map to prevent accidental access of invalid memory after calling destroy. Or if you want to protect against this you should throw an exception.
6) If you're not using polymorphic T then you could use a std::map and your code would look like this...
That's about all I can think of for now.
一项改进是重写
getRef
以使用getPtr
(反之亦然,方向并不重要,不重复自己):One improvement would be to rewrite
getRef
to usegetPtr
(or vice versa, the direction doesn't matter so much as not repeating yourself):看来你的工作做得非常令人印象深刻。
顺便说一句,我可以问一下为什么你在这里投射实例(c 风格)吗?
我认为如果你只写的话会更干净
另外,因为这篇文章已经有 10 年历史了,
我使用智能指针以现代 C++ 方式进行了一点版本升级。
请看一下!
multiton.h
multiton.cpp
It seems you did very impressive job.
BTW, may I ask why you casted instance (in c-style) here?
I think It would be cleaner if you just write
Additionally, as this post is 10-years old,
I versioned-up a little bit in modern c++ way, using smart pointer.
Please take a look!
multiton.h
multiton.cpp