In my mind, always, definition means storage allocation.
In the following code, int i allocates a 4-byte (typically) storage on program stack and bind
Your code is fine. The variable lives wherever it would live had the goto not been there.
Note that there are situations where you can't jump over a declaration:
C++11 6.7 Declaration statement [stmt.dcl]
3 It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5). [ Example:
void f() { // ... goto lx; // ill-formed: jump into scope of `a' // ... ly: X a = 1; // ... lx: goto ly; // ok, jump implies destructor // call for `a' followed by construction // again immediately following label ly }—end example ]