2016-04-14 67 views
-1

我正在开发一个容器模板类。此代码需要与现有的C代码连接,并且需要保持二进制兼容,因此我不能使用即std::vector或类似代码。选择一种方法作为(默认)模板参数

我的问题是它需要支持不同的分配策略,我不知道如何提供分配器作为模板参数。我创建了一个SSCCE来说明我得到了多少(当然不会编译,因为如果它会的话,我不需要问这个问题:))。

#include <iostream> 
#include <cstring> 
#include <type_traits> 

typedef unsigned int  uint_t; 
typedef signed int   int_t; 

template <typename T, typename S, typename _allocator = _virtual> 
class Container 
{ 
public: 
    Container(S nItems = 0, S nMaxItems = 0, T *pArray = NULL) 
    { 
     mItems = nItems; 
     mMaxItems = nMaxItems; 
     mArray = pArray; 
    } 

    void adjustMalloc(uint_t nClusterSize) 
    { 
     if(mItems == mMaxItems) 
     { 
      mArray = (T *)realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T)); 
      mMaxItems += nClusterSize; 
     } 
    } 

    void adjustAligned(uint_t nClusterSize) 
    { 
     if(mItems == mMaxItems) 
     { 
      mArray = (T *)_aligned_realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), 16); 
      mMaxItems += nClusterSize; 
     } 
    } 

    void adjustVirtual(uint_t nClusterSize) 
    { 
     if(mItems == mMaxItems) 
     { 
      mArray = VirtualAlloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), MEM_RESERVE, PAGE_NOACCESS); 
      mMaxItems += nClusterSize; 
     } 
    } 

    void adjust(uint_t nClusterSize) 
    { 
     if (std::is_same<_allocator>::value == _virtual) 
      adjustVirtual(nClusterSize); 
     else if(std::is_same<_allocator>::value == _aligned) 
      adjustAligned(nClusterSize); 
     else if(std::is_same<_allocator>::value == _malloc) 
      adjustMalloc(nClusterSize); 
     else 
     { 
      // Cause a static compiler error, how? 
     } 
    } 

    bool add(T *pItem) 
    { 
     if(find(pItem) == NULL) 
     { 
      adjust(100); 
      mItems++; 

      return true; // added 
     } 

     return false; 
    } 

    T *find(T *pItem) 
    { 
     T *p = mArray; 

     for(S i = 0; i < mItems; i++, p++) 
     { 
      if(*p == *pItem) 
       return p; 
     } 

     return NULL; 
    } 

private: 
    S mItems; 
    S mMaxItems; 
    T *mArray; 
}; 


class Record 
{ 
public: 

    bool operator==(const Record &oRecord) 
    { 
     if(Id != oRecord.Id) 
      return false; 

     if(strcmp(Name, oRecord.Name) != 0) 
      return false; 

     return true; 
    } 

    int Id; 
    char Name[10+1]; 
}; 

int main(int argc, char *argv[]) 
{ 
    Record rec; 
    rec.Id = 0; 
    strcpy(rec.Name, "Test"); 

    Container<Record, uint_t> records; // Default using malloc 
    records.add(&rec); 

    if(records.find(&rec) == NULL) 
     std::cerr << "Not found" << std::endl; 

    Container<Record, uint_t, _virtual> vrecords; // VirtualAlloc allocator used. 
    vrecords.add(&rec); 

    if(records.find(&rec) == NULL) 
     std::cerr << "Not found" << std::endl; 

    return 0; 
} 

我在使用Visual Studio 2010,因此它不是100%C++ 11。

提供的VirtualAlloc只是(另一个)示例,不能像这里显示的那样工作。

+0

重载'vector'如何解决你的接口问题? – Barry

+0

这与答案有关吗? – Devolus

+0

是的。现在你的'Container'有几个问题,所以我想知道这个方法实际上给你带来了什么,只是使用'vector'不会(或者真的是'std :: set',基于'add'做什么) – Barry

回答

-1

我找到了解决我的问题的方案。不过,我得到的警告

warning C4127: conditional expression is constant

adjust()方法为if(std::is_same...,我想知道,这是正常的,或者如果我能摆脱它,不要禁用它其他。

#include "stdafx.h" 
#include "windows.h" 

#include <iostream> 
#include <cstring> 
#include <type_traits> 

#pragma warning (push) 
//#pragma warning (disable : 4127) 

typedef unsigned int  uint_t; 
typedef signed int   int_t; 

typedef struct { const static bool _virtual_allocator = true; } _virtual_type; 
typedef struct { const static bool _aligned_allocator = true; } _aligned_type; 
typedef struct { const static bool _malloc_allocator = true; } _malloc_type; 

template <typename T, typename S, typename _allocator = _aligned_type> 
class Container 
{ 
public: 
    Container(S nItems = 0, S nMaxItems = 0, T *pArray = NULL) 
    { 
     mItems = nItems; 
     mMaxItems = nMaxItems; 
     mArray = pArray; 
    } 

    void adjustMalloc(uint_t nClusterSize) 
    { 
     if(mItems == mMaxItems) 
     { 
      mArray = (T *)realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T)); 
      mMaxItems += nClusterSize; 
     } 
    } 

    void adjustAligned(uint_t nClusterSize) 
    { 
     if(mItems == mMaxItems) 
     { 
      mArray = (T *)_aligned_realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), 16); 
      mMaxItems += nClusterSize; 
     } 
    } 

    void adjustVirtual(uint_t nClusterSize) 
    { 
     if(mItems == mMaxItems) 
     { 
      mArray = (T *)VirtualAlloc((LPVOID)mArray, (mMaxItems+nClusterSize)*sizeof(T), MEM_RESERVE, PAGE_NOACCESS); 
      mMaxItems += nClusterSize; 
     } 
    } 

    void adjust(uint_t nClusterSize) 
    { 
     if (std::is_same<_allocator, _virtual_type>::value) 
      adjustVirtual(nClusterSize); 
     else if(std::is_same<_allocator, _aligned_type>::value) 
      adjustAligned(nClusterSize); 
     else if(std::is_same<_allocator, _malloc_type>::value) 
      adjustMalloc(nClusterSize); 
     else 
     { 
      // Cause a static compiler error, how? 
     } 
    } 

    bool add(T *pItem) 
    { 
     if(find(pItem) == NULL) 
     { 
      adjust(100); 
      mItems++; 

      return true; // added 
     } 

     return false; 
    } 

    T *find(T *pItem) 
    { 
     T *p = mArray; 

     for(S i = 0; i < mItems; i++, p++) 
     { 
      if(*p == *pItem) 
       return p; 
     } 

     return NULL; 
    } 

private: 
    S mItems; 
    S mMaxItems; 
    T *mArray; 
}; 

#pragma warning (pop) 

class Record 
{ 
public: 
    bool operator==(const Record &oRecord) 
    { 
     if(Id != oRecord.Id) 
      return false; 

     if(strcmp(Name, oRecord.Name) != 0) 
      return false; 

     return true; 
    } 

    int Id; 
    char Name[10+1]; 
}; 

int main(int argc, char *argv[]) 
{ 
    Record rec; 
    rec.Id = 0; 
    strcpy(rec.Name, "Test"); 

    Container<Record, uint_t> mrecords; 
    mrecords.add(&rec); 

    if(mrecords.find(&rec) == NULL) 
     std::cerr << "Malloc Not found" << std::endl; 

    Container<Record, uint_t, _aligned_type> arecords; 
    arecords.add(&rec); 

    if(arecords.find(&rec) == NULL) 
     std::cerr << "Aligned Not found" << std::endl; 

    Container<Record, uint_t, _virtual_type> vrecords; 
    vrecords.add(&rec); 

    if(vrecords.find(&rec) == NULL) 
     std::cerr << "Virtual Not found" << std::endl; 

    return 0; 
} 
+0

为什么downvote? – Devolus