Andrew is correct; I will merely add a couple of extra details.
First off, the correct way to think of out/ref parameters is that they are aliases for variables. That is, when you have a method M(ref int q) and call it M(ref x), q and x are two different names for exactly the same variable. A variable is a storage location; you store something in q, you're storing it in x too, because they are two different names for the same location.
Second, the alternative you're describing is called "copy in / copy out" referencing. In this scheme there are two storage locations and the contents of one are copied in upon the function call beginning, and copied back out when its done. As you note, the semantics of copy-in-copy-out are different than the semantics of alias references when exceptions are thrown.
They are also different in bizarre situations like this:
void M(ref int q, ref int r)
{
q = 10;
r = 20;
print (q);
}
...
M(ref x, ref x);
In aliasing, x, q and r are all the same storage location, so this prints 20. In copy-in-copy-out referencing, this would print 10, and the final value of x would depend on whether the copy-out went left to right or right to left.
Finally, if I recall correctly, there are rare and bizarre scenarios in the implementation of expression trees where we actually implement copy-in-copy-out semantics on ref parameters. I should review that code and see if I can remember what exactly those scenarios are.