代码之家  ›  专栏  ›  技术社区  ›  mans

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

  •  3
  • mans  · 技术社区  · 7 年前

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

    #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黑客,在C++上不支持。

    Array with size 0

    Array of zero length

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

    如何在C++中做到这一点

    2 回复  |  直到 7 年前
        1
  •  1
  •   Daniel Langr    7 年前

    像这样的东西怎么样?它适用于 微不足道的可复制 类型:

    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

        2
  •  1
  •   Yakk - Adam Nevraumont    7 年前
    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
    }
    

    我相信这是符合标准的,假设您的实现没有在普通类型的数组(如char)上添加填充。我不知道它的任何实现。

    我没想到 MyData 只包含简单的旧数据;您可以填充 std::vector 和上面的一样。我可以用这个假设简化几行。

    这不仅仅是一点痛苦。

    auto foo = MyData::create(100) 创建唯一的ptr到 MyDATA 有100个缓冲区 int 在后面。 (*foo)[77] 访问缓冲区的第77个元素。

    由于标准中存在缺陷,在 MyDATA 而是一个包含100个不同的 int 相邻内存位置中的对象。这两件事之间有一些令人恼火的区别;幼稚的指针算术可以保证在数组中工作,但不能在压缩的相邻数组之间工作。 int 在缓冲器中。我不知道有哪个编译器会强制执行这种差异。