更好的方法吗?

时间:2010-10-29 17:05:22

标签: c++

我正在做一些似乎可以改进的事情,但我没有足够的技巧来改进它。你能帮忙吗?

假设:

vector<Base*> stuff;
const vector<MetaData>& metaDataContainer = Config.getMetaData();

for(vector<MetaData>::const_iterator i = metaDataContainer.begin(), end = metaDataContainer.end(); i != end; ++i)
{
  Base* pCurrent = buildDerivedType(*i);
  stuff.push_back(pCurrent);
}

Base* buildDerivedType(MetaData meta)
{
  Base* pRetval = NULL;

  switch(meta)
  {
    case MetaData::A:
    pRetval = new Alpha();
    break;

    case MetaData::B:
    pRetval = new Beta();
    break;

    //so on so forth
  };
  return pRetval;
}

我觉得switch语句很糟糕,因为在编译时所有的枚举值都是已知的,所以理论上我们已经知道需要进入向量内容的类型。但是我们在运行时这样做。

没有为此编写代码生成器,有更好的方法吗?

4 个答案:

答案 0 :(得分:3)

不是真的。但是,您可以使用factory type抽象掉大部分样板,并使用boost::ptr_vector或智能指针容器以智能方式管理资源。 (See comments关于智能容器与智能指针的哑容器之间的选择。)

答案 1 :(得分:3)

好吧,你可以预先分配一个映射元 - &gt;创建所需派生类型的函数。

typedef Base* ((*DerivedTypeCreator)());
map <MetaData, DerivedTypeCreator> derivedTypeBuilders;

// ...
derivedTypeBuilders[MetaData::A] = &CreateAlpha;
derivedTypeBuilders[MetaData::B] = &CreateBeta;

Base* CreateAlpha()
{
    return new Alpha();
}

Base* CreateBeta()
{
    return new Beta();
}

// ...
for(vector<MetaData>::const_iterator i = metaDataContainer.begin(),
        end = metaDataContainer.end();
    i != end; ++i)
{
    stuff.push_back((*(derivedTypeBuilders[*i]))());
}

请不要忘记考虑meta的值不在地图中的情况!

对于特定情况,如果您的元数据值是小数字,您甚至可以消除运行时开销:

DerivedTypeCreator[] derivedTypeBuilders = {
    &CreateAlpha, // Metadata::A == 0
    &CreateBeta   // Metadata::B == 1
};

// ...
stuff.push_back((*(derivedTypeBuilders[(int)*i]))());

- 但这种方法可能太低级且容易出错。 (希望C ​​++语法允许这样的初始化。)

答案 2 :(得分:2)

template<class T> Base* Creator() { return new T; }
typedef Base* (*CreateType)();
typedef std::pair<const MetaData, CreateType> cpair;

cpair mapper [] =
{
    cpair(MetaA, Creator<A>),
    cpair(MetaB, Creator<B>),
};

std::map<MetaData, CreateType> typemap(&mapper[0], &mapper[sizeof(mapper)]);

void foo(MetaData m)
{
    Base* a = typemap[m]();
}

答案 3 :(得分:0)

您在询问工厂模式。你可以google。要尽可能多地放入编译时(w.r.t.运行时),您可能希望使用模板添加搜索词

但是,由于你的“元数据向量”包含运行时的信息,你需要一些动态的东西。 enum并不是一个坏主意 - 请看这里,例如:http://www.daniweb.com/forums/thread18399.html。 另请注意typedef InstantiatorMap::value_type InstantiatorMapEntryType末尾的位。使用'enums''到''成员函数指针''作为工厂的映射。