What you posted works, along with Jeremiah Willcock's solution using istringstream instead. But consider using the scanf family of functions as well (for just a couple of ints it doesn't make much of a difference, but for more advanced input, using scanf can be much more concise than messing around with stream manipulators):
string things = "10 11 12 -10";
int i1, i2, i3, i4, i5, i6;
sscanf(things.c_str(), "%d %d %d %d", &i1, &i2, &i3, &i4);
The reason your example just gives 0's after that is because the stringstream buffer is empty once you extract the -10: you'll have to insert more into the buffer before you can extract more. You can use the same stringstream instance multiple times, but you'll either need to fully use the buffer each time, or realize that there's more in the buffer before the next item you insert into the buffer:
string things = "10 11 12 -10", temp;
int i1, i2, i3, i4;
stringstream into;
into << things; //buffer is now "10 11 12 -10"
into >> i1; //buffer is now " 11 12 -10"
into >> i2; //" 12 -10"
into >> i3; //" -10"
into >> i4; //""
//more code here...
//come back and use the instance again
into << "more: 1 2 3"; //"more: 1 2 3"
into >> temp; //temp is "more:"; into's buffer is " 1 2 3"
into >> i1; //buffer is " 2 3"
//more code here...
//reuse into once again
into << "4 5 6"; // buffer is now " 2 3 4 5 6"
into >> i1; //i1 gets the 2 from before, not the 4 just inserted; buffer now " 3 4 5 6"
into >> i2; //i2==3; buffer is " 4 5 6"
Also, ios (from which stringstream inherits) also defines the ! operator and a cast to void* so that you can conveniently check if extraction failed (technically checks if failbit or badbit is set, and I believe failbit is the one that gets set along with eofbit when there's not enough in the buffer):
string things = "10 11 12 -10";
int i1, i2, i3, i4;
stringstream into;
into << things;
into >> i1 >> i2 >> i3 >> i4;
if (into >> i5) {
cout << "extraction to i5 succeeded" << endl;
}
if (!(into >> i6)) {
cout << "extraction to i6 failed" << endl;
}