C ++创建具有可变数量项的结构的方法

时间:2018-05-28 12:45:21

标签: c++ c++11

我需要在末尾创建一个包含可变数量项的内存区域。我可以这样写的东西:

#pragma pack(push,0)
struct MyData
{
    int noOfItems;
    int buffer[0];
};
#pragma pack(pop)

MyData * getData(int size)
{
     bufferSize = size* sizeof(int) + sizeof(MyData ::noOfItems);
     MyData * myData= (MyData *)new char[m_bufferSize];
     return myData;
}

此代码适用于VS 2015,警告大小为零的数组不是标准

一些搜索向我显示这是一个C hack并且在C ++上不受支持。

Array with size 0

Array of zero length

What happens if I define a 0-size array in C/C++?

如何在C ++中执行此操作

2 个答案:

答案 0 :(得分:1)

这样的事情怎么样?它适用于平易可复制的类型:

template <typename T, typename INT = size_t>
class packed_array {
  public:
    packed_array(INT size) {
      buf_ = new char[sizeof(INT) + size * sizeof(T)];
      memcpy(buf_, &size, sizeof(INT));
    }
    ~packed_array() { delete[] buf_; }

    void set(INT index, T val) {
      memcpy(buf_ + sizeof(INT) + index * sizeof(T), &val, sizeof(T));
    }
    T get(INT index) const {
        T temp;
        memcpy(&temp, buf_ + sizeof(INT) + index * sizeof(T), sizeof(T));
        return temp;
    }

    const char* data() const { return buf_; }

  private:
    char* buf_;

  static_assert(std::is_trivially_copyable<T>::value);
};

int main() {
  int n;
  std::cin >> n;
  packed_array<double, int> a(n);
  for (int i = 0; i < n; i++)
    a.set(i, pow(2.0, i)); 
  for (int i = 0; i < n; i++)
    std::cout << a.get(i) << std::endl;
}

现场演示:https://wandbox.org/permlink/Vc4ok756R1Sxieoj

答案 1 :(得分:1)

//in libstatic1.a
//...
0000000000000000 T _testcmethds
//...

//in libstatic2.a
//...
0000000000000000 T _testcmethds
//...

我认为这是标准兼容的,假设你的实现没有在普通类型的数组(如char)上添加填充。我不知道任何实现。

我没想到template<class T, class D> struct var_array_at_end { var_array_at_end( std::size_t N ) { ::new( (void*)data() ) std::aligned_storage_t<sizeof(T)*N, alignof(T)>; for (std::size_t i = 0; i < N; ++i) { ::new( (void*)( data()+sizeof(T)*i) ) ) T(); } } char* data() { return reinterpret_cast<char*>(this)+sizeof(D); } char const* data() const { return reinterpret_cast<char*>(this)+sizeof(D); } T* ptr(std::size_t i = 0) { return reinterpret_cast<T*>( data()+sizeof(T)*i ); } T const* ptr(std::size_t i = 0) const { return reinterpret_cast<T*>( data()+sizeof(T)*i ); } T& operator[](std::size_t n) { return *ptr(n); } T const& operator[](std::size_t n) const { return *ptr(n); } }; struct MyData: var_array_at_end<int, MyData> { private: explicit MyData( int count ): var_array_at_end<int, MyData>( count>0?(unsigned)count:0 ), noOfItems(count) {} struct cleanup { void operator()(MyData* ptr) { char* buff = reinterpret_cast<char*>(ptr); ptr->~MyData(); delete[] buff; } }; public: using up = std::unique_ptr<MyData*, cleanup>; static up create( int count ) { if (count < 0) count = 0; std::unique_ptr<char> buff = std::make_unique<char[]>( sizeof(MyData)+sizeof(int)*count ); auto* ptr = ::new( (void*)buff.get() ) MyData( count ); (void)buff.release(); return up( ptr, {} ); } int noOfItems; }; MyData * getData(int size) { return MyData::create(size).release(); // dangerous, unmanaged memory } 只包含普通旧数据;你可以用上面的内容填充MyData。我可以用这个假设简化几行。

这不仅仅是一种痛苦。

std::vectorauto foo = MyData::create(100)创建一个唯一的ptr,其后面有100 MyData s的缓冲区。 int访问缓冲区的第77个元素。

由于标准中存在缺陷,您在(*foo)[77]之后没有数组,而是在相邻内存位置包含100个不同MyData对象的缓冲区。这两件事之间存在着令人烦恼的差异; naive指针arithimetic保证在数组内工作,但不能在缓冲区中打包的相邻int之间工作。我不知道一个强制执行这种差异的编译器。