写c或者c++,代码稍微复杂点,肯定会用到union;union支持普通的不带structor的结构或者class
但绝对不支持带构造函数的class,原因其实想下也清楚;
所以一般碰到这种问题的时候,都只能走其他途径绕开这个问题;比如一般稍微复杂点的svr中用到
的状态机,状态机里面会保存request的拷贝,一般一个svr里面多类请求会公用一套fsm;需要保存所有类型
的request,如果有union的话,那就比较简单了:
class Fsm...{
union {
TRequest1 req1;
TRequest2 req2;
TRequest3 req3;...
}request;
};
不行,所以只能采用
class Fsm... {
TRequest1 req1;
TRequest2 req2;
TRequest3 req3;
};
这样问题有几个:
1,内存浪费,如果只有2,3类还好,如果有10来中request,那每个fsm就会无谓的占
用不必要的内存了;
2,看起来难受,用起来其实不方便,写代码写起来麻烦啰嗦,像上面那种req1,req2,req3...
想了想,于是写了个能保存带构造函数的类union来;用起来还算ok;
代码如下,另外有单元测试,用法可以参考单元测试;
现在如果需要完成fsm,就可以写成:
class Fsm... {
ClassContainer<TRequest1, TRequest2, TRequest3> _input_req;
};
- #include <stdlib.h>
- #include <unistd.h>
- #include <boost/preprocessor/repetition.hpp>
- #include "shortcuts_util.h"
- #define MAX_CLASS_NUM 21
- namespace _OX_
- {
- #define CREATE_STRUCT(n) \
- struct T ## n {};
- REPEATE_MACRO(MAX_CLASS_NUM, CREATE_STRUCT);
- #undef CREATE_STRUCT
- }
- template<typename T0, typename T1, typename T2 = _OX_::T0, typename T3 = _OX_::T1, typename T4 = _OX_::T2, typename T5 = _OX_::T3, typename T6 = _OX_::T4,
- typename T7 = _OX_::T5, typename T8 = _OX_::T6, typename T9 = _OX_::T7, typename T10 = _OX_::T8, typename T11 = _OX_::T9, typename T12 = _OX_::T10, typename T13 = _OX_::T11,
- typename T14 = _OX_::T12, typename T15 = _OX_::T13, typename T16 = _OX_::T14, typename T17 = _OX_::T15, typename T18 = _OX_::T16, typename T19 = _OX_::T17, typename T20 = _OX_::T18>
- class ClassContainer
- {
- public:
- ClassContainer() : _type(-1)
- {
- }
- ~ClassContainer()
- {
- free();
- }
- int get_type() const
- {
- return _type;
- }
-
- void* get_raw_data()
- {
- return _cls_mem;
- }
- template<typename Ttarget>
- Ttarget *get_class(Ttarget* target, bool strictly = false)
- {
- return get_class<Ttarget>(strictly);
- }
- template<typename Ttarget>
- Ttarget *get_class(bool strictly = false)
- {
- static Ttarget target;
- int type = get_type(target);
- if (_type != type)
- {
- if (strictly)
- assert(0);
- if (_type != -1)
- free();
- init(type);
- }
- return (Ttarget *)_cls_mem;
- }
- #define CREATE_TYPE_FUNC(n) \
- int get_type(const T ## n & tar) const \
- { \
- return n; \
- }
- REPEATE_MACRO(MAX_CLASS_NUM, CREATE_TYPE_FUNC);
- #undef CREATE_TYPE_FUNC
- void init(int type)
- {
- assert(_type == -1);
- switch (type)
- {
- #define CONSTRUCT_CLASS(n) \
- case n: { \
- ::new (_cls_mem)T ## n; \
- break; \
- }
- REPEATE_MACRO(MAX_CLASS_NUM, CONSTRUCT_CLASS);
- #undef CONSTRUCT_CLASS
- default:
- assert(0);
- }
- _type = type;
- }
- void free()
- {
- if (_type == -1)
- return;
- switch (_type)
- {
- #define DESTORY_CLASS(n) \
- case n: { \
- ((T ## n *)_cls_mem)->~T ## n(); \
- break; \
- }
- REPEATE_MACRO(MAX_CLASS_NUM, DESTORY_CLASS);
- #undef DESTORY_CLASS
- default:
- assert(0);
- }
- _type = -1;
- }
- private:
- union _AllTypes {
- #define TYPE_SIZE(n) \
- char _f ## n[sizeof(T ## n)];
- REPEATE_MACRO(MAX_CLASS_NUM, TYPE_SIZE);
- #undef TYPE_SIZE
- };
- private:
- char _type;
- char _cls_mem[sizeof(_AllTypes)];
- };
- /*
- ******************************** UNIT TEST ********************************
- */
- #include <gtest/gtest.h>
- #include <vector>
- #include <map>
- #include <string>
- using namespace testing;
- class ClassContainerTestCase : public testing::Test
- {
- };
- TEST_F(ClassContainerTestCase, Test)
- {
- typedef std::vector<std::string> VType;
- typedef std::map<int64_t, int> MType;
- ClassContainer<VType, MType, int64_t> cls_container;
- ASSERT_EQ(sizeof(cls_container), std::max(sizeof(VType), sizeof(MType)) + 1);
- cls_container.get_class<VType>()->resize(100);
- ASSERT_EQ((int)cls_container.get_class<VType>()->size(), 100);
- MType m_buf;
- m_buf[0x5555998] = 50;
- m_buf[0x89898977] = 10;
- m_buf[0x89898475] = 8;
- *(cls_container.get_class<MType>()) = m_buf;
- ASSERT_EQ((*cls_container.get_class<MType>())[0x89898977], 10);
- ASSERT_TRUE(cls_container.get_class<VType>()->empty());
- ASSERT_EQ(*cls_container.get_class<int64_t>(), 0);
- }
阅读(1624) | 评论(0) | 转发(0) |