Well, the alternative way to bypass copying is to use the "return parameter" idiom instead of using the return value of the function
void getAllAbove(Triangle* t, std::list<Triangle*>& result);
Instead of forming the result "on the stack" as you do now, form it directly in result
parameter (i.e. in the recipient list that you pass from the caller).
As for your original code, whether the copying will take place or not depends on the capabilities of your compiler.
From the most abstract point of view, your code actually has two copyings. (And yes, these are full-fledged copyings when the entire content of the list is meticulously duplicated in another list, element by element.) Firstly, the named list object you create on the stack inside your function is copied to a nameless temporary object that holds the return value of the function. Then the temporary object is copied to the final recipient object in the calling code. Most compilers will be able to eliminate one of these copyings (to eliminate the intermediate temporary, as allowed by C++98 specification).
To eliminate the second one the compiler has to be able to perform so called Named Return Value Optimization (as allowed by C++03 specification). A compiler that supports Named Return Value Optimization should be able to essentially implicitly convert your function's interface into the equivalent of the above "return parameter" idiom. I would expect GCC to be able to do it. Try it and see what happens.