You do not need reserve, and if one of the 20 bytes you read from stdin is \0 you will fill only a few bytes.
Here is the correct code:
char * foo = new char [20];
read(STDIN_FILENO, foo, 20);
string bar;
bar.assign(foo, 20);
delete[] foo;
...you may have problems with an exception on std::string (constructor or assign), but memory exception IMHO should be handled only if you allocate large quantity of memory, because if an allocation of 20 bytes fails most surely you will not be able to properly handle an exception.
If I had to improve your code, both for speed and safety I'll do it this way:
char foo[20];
int len = read(STDIN_FILENO, foo, sizeof(foo));
string bar;
if (len > 0)
bar.assign(foo, len);