【问题标题】:Control dynamically the number of members in c++ data structure动态控制 c++ 数据结构中的成员数
【发布时间】:2012-10-22 01:40:34
【问题描述】:

我目前正在编写一个处理数据库的程序。

我可以要求不同的选项并获得可变数量的列。

问题是数据将是千兆字节的信息,我无法创建一个包含所有可能选项的结构。我需要能够动态创建一个结构,其中只有我需要的成员,没有别的。

我还想要比为每个可能的情况创建一个结构更好的东西!

以下是表格示例:

smallint(6) - varchar(255) - double - int(11)
smallint(6) - varchar(255) - double - double - double - int(11)
smallint(6) - smallint(6) - varchar(255) - varchar(255) - double - int(11)

有什么方法可以在 c++ 中创建具有动态成员数量的结构,并且与普通结构一样高效?

[编辑]

这是一个使用@Industrial-antidepressant 想法的解决方案。它可以工作,但唯一的问题是它似乎比普通结构慢 4 倍。

#include <windows.h>

class Column
{
public:
    Column(uint64 nOffset, const type_info* pType)
    {
        m_nOffset = nOffset;
        m_pType = pType;
    }

    uint64 m_nOffset;
    const type_info* m_pType;
};


struct UWElement
{
public:
    template<class T>
    void Set(uint64 nColumn, T value)
    {
        if ((*m_pColumnList)[nColumn].m_pType == &typeid(T))
        {
            uint64 nOffset = (*m_pColumnList)[nColumn].m_nOffset;
            *(reinterpret_cast<T*>(m_pData + nOffset)) = value;
        }
        else
        {
            assert(0);
        }
    }

    template<class T>
    T& Get(uint64 nColumn)
    {
        // No type check here to test speed
        uint64 nOffset = (*m_pColumnList)[nColumn].m_nOffset;
        return *reinterpret_cast<T*>(m_pData + nOffset);
    }

protected:
    unsigned char* m_pData;
    std::vector<Column>* m_pColumnList;

    friend class UWElementList;
};



class UWElementList
{
public:
    UWElementList()
    {
        m_nEndOffset = 0;
    }

    template<class T>
    void AddType()
    {
        Column column(m_nEndOffset, &typeid(T));
        m_columnlist.push_back(column);
        m_nEndOffset += sizeof(T);
    }

    void CreateElement()
    {
        UWElement element;
        element.m_pData = new unsigned char[m_nEndOffset];
        element.m_pColumnList = &m_columnlist;
        m_elementList.push_back(element);
    }

    UWElement& operator[](int64 nPos)
    {
        return m_elementList[nPos];
    }

private:
    std::vector<Column> m_columnlist;
    uint64 m_nEndOffset;

    std::vector<UWElement> m_elementList;
};


int main()
{
    struct SimilarStruct
    {
        double a;
        int b;
        int c;
    };

    SimilarStruct similar;
    vector<SimilarStruct> similarList;
    similarList.push_back(similar);

    UWElementList list;
    list.AddType<double>();
    list.AddType<int>();
    list.AddType<int>();
    list.CreateElement();

    // Test writing speed
    uint64 nTick = GetTickCount64();
    for(int i=0; i<100*1000*1000; i++)
    {
        //list[0].Set<double>(0,(double)1.1);       //Speed 140ms
        list[0].Get<double>(0) = (double)1.1;   //Speed 109ms
        //similarList[0].a = (double)1.1;           //Speed 31ms
    }
    cout << GetTickCount64() - nTick << endl;

    double d=0;

    // Test reading speed
    nTick = GetTickCount64();
    for(int i=0; i<100*1000*1000; i++)
    {
        d += list[0].Get<double>(0);                //Speed 94ms
        //d += similarList[0].a;                        //Speed 93ms
    }
    cout << GetTickCount64() - nTick;


    return d;
}

任何可以帮助加快速度的优化?

【问题讨论】:

  • 拥有这些数据后需要做什么?
  • 数据会用列号索引吗?然后你需要一个带有起始数据索引的标题结构,你需要一个保存列数据的内存块,你需要使用标题索引和 reinterpret_cast 二进制数据的模板化 get 和 set 方法
  • @Industrial-antidepressant 这是我认为唯一可行的解​​决方案,但我发现需要将标题结构带到任何使用数据的地方并不那么优雅。此解决方案还可能引入难以解决的错误并破坏堆
  • @VaughnCato 我会迭代很多次,并尽可能快地读取每一列的所有值。
  • 如何将每一列保存在适当类型的向量中?由于更好的打包,它可能比结构向量更有效。

标签: c++ optimization data-structures c++11 containers


【解决方案1】:

如果您愿意使用 Boost 库,这里有一些想法。

您可以尝试使用boost::variant&lt;list of possible types&gt; 的二维数组。对于动态二维数组,可以使用boost::multi_array

根据文档,boost::variant 有一个:

高效实现——尽可能基于堆栈(请参阅第 详情请致电“"Never-Empty" Guarantee”)。

我之前成功地使用了boost::variant 的向量来表示数据库行,但我的内存需求比你的要低得多。您可能必须对这种方法进行基准测试,看看它是否可行。

如果您使用这种方法,您可能需要某种方法在运行时确定给定数据库列的索引。如果要按名称访问列,可以使用std::mapboost::unordered_map 来进行列名和列索引之间的映射。

希望这会有所帮助。

【讨论】:

  • boost::variant 将不起作用,因为每个变体对象使用 16 字节,这将使我的列表大小增加一倍以上。
【解决方案2】:

如何使用链接列表。您可以使用 new 运算符为每个节点动态分配内存。

性能可能不等于使用预定义结构时获得的性能,但它提供了更多控制。

如果您仍然只想创建动态结构,可以在结构中使用联合。

更多信息:Dynamic structures in C++

【讨论】:

  • 内存分配能否应对 1 亿个对象,每个对象都有 4 到 10 个元素的链表?
  • 会一次性使用全部 1 亿个对象吗?我希望不是。您必须在需要时继续分配/取消分配。
  • 是的,我确实同时需要它们,这就是问题所在。我现在在一个固定的数据结构中批量加载它们,它工作得很好而且很快。我现在无法想象如何创建一个快速的动态结构。
  • 如果是这样的话,我不会推荐链接列表。也许在结构内部使用联合?
猜你喜欢
  • 1970-01-01
  • 2021-01-25
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
相关资源
最近更新 更多