will the implicitly synthesized move constructor just make this in y point to the memory that x is in?
As Anoop noted, it will memberwise call the move constructor on every member of the source to be moved (x) onto the members of the destination (y or this if you imagine yourself "inside" that synthesized move constructor).
So in your example:
- the intx.iwill be moved ontoy.i(this->i)
- the int*x.ptrwill be moved ontoy.ptr(this->ptr).
Note that these particular moves will be performed by copying.
how to ensure that x is destructible after the move (if x is destroyed, will members in y be valid)?
It's always destructible.  As to if it's "valid", it depends. The default move construction was actually a copy.  Two objects now point at whatever x.ptr pointed to.  If that int was a resource "owned" by x (maybe the resource was a 0 terminated string of ints on the heap), then you've just "shared" that resource.
If you don't wish to "share" it then you could have explicitly written a move constructor for Foo that resets the pointer of the "moved-from" object, or somehow marks it invalid.
struct Foo {
  ...
  Foo(Foo&& other) {
    this->i = other.i;
    this->ptr = other.ptr;
    other.ptr = nullptr;
  }
}
In general, it's best not to rely on "moved from" objects at all, i.e. make sure they are destroyed as soon as possible.