There's a subtle difference between the two where in the first case you're copying valid values to another valid variable while in the second there's no way to save the "result".
In the first occurrence you're using a temporary value on the stack to create your vector but then you're returning it and copy-assigning a value to another variable that you can safely use
stNameAge nameage = GetNamesAndAges()[0];
In the second you're creating a temporary vector, requesting an element but asking for a pointer to that element. When the vector gets destroyed, the pointer is no longer valid
char* MyName2 = GetNamesAndAges()[0].Name ;
Can you see the difference between the two cases?
In pseudo-code we might summarize with the following
int nameage;
int *pointer;
{
int value = 44; // The value you're interested in
nameage = value; // You can safely use nameage from this point forward
pointer = &value; // When the scope ends, there's no guarantee you'll be pointing to valid data
}
// nameage is valid here, pointer is likely not and even if it is it's undefined behavior