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
}
I believe this is standard compliant, assuming your implementation doesn't add padding on arrays of trivial types (like char).  I am unware of any implementation thta does.
I didn't assume that MyData only contains plain old data; you could stuff a std::vector into it with the above.  I might be able to simplify a few lines with that assumption.
It is more than a bit of a pain.
auto foo = MyData::create(100) creates a unique ptr to MyData that has a buffer of 100 ints after it.  (*foo)[77] accesses the 77th element of the buffer.
Due to a defect in the standard, you there isn't an array after MyData but rather a buffer containing 100 distinct int objects in adjacent memory locations.  There are vrey annoying differences between those two things; naive pointer arithimetic is guaranteed to work within arrays, but not between packed adjacent ints in a buffer.  I am unaware of a compiler that enforces that difference.