If you return an lvalue expression from a function, and this lvalue:

If all of these are the case, then the copy/move from the lvalue can be elided:

std::string func()
{
  std::string str("foo");
  //Do stuff
  return str;
}

More complex cases are eligible for elision, but the more complex the case, the less likely the compiler will be to actually elide it:

std::string func()
{
  std::string ret("foo");
  if(some_condition)
  {
    return "bar";
  }
  return ret;
}

The compiler could still elide ret, but the chances of them doing so go down.

As noted earlier, elision is not permitted for value parameters.

std::string func(std::string str)
{
  str.assign("foo");
  //Do stuff
  return str; //No elision possible
}