1st question: Is this the proper way to render triangles? This will usually work, but not always (see below for details).
2nd question: If I'm sorting all the objects, this is n*log(n) now. Is this the most efficient way to do this? Probably, unless you know something special about the triangles before you start drawing them (e.g., if you are drawing a surface that doesn't fold over itself, you can do it quicker because any order will work).
Some details on the 1st question:
I think I'm working on the same problem. I create a list of triangles using triples of (x,y,z) coordinates and then send them in order to a draw_triangle method. None of my triangles overlap (i.e., none puncture or slice through each other). However, the "back to front" approach using distance does not always work. It occasionally draws some triangles in front of others when they should be behind them.
Stephen's response that "you could probably just do sorting back to front" is fairly accurate, as this works almost all of the time for normal cases. However, I started noticing errors and eventually determined that the cause was the ordering algorithm that did back to front by distance.
A simple counter-example is two triangles arranged like a bowtie, where they overlap in the middle near their vertices. Assume the right triangle is slightly behind the left triangle. Now rotate the entire bowtie as a single unit so that the right side comes forward and the left goes back. Using "back to front" based on distance, the left triangle is drawn first because it is farther away. However, the correct order is to draw the right triangle first, because it is behind the left one where they overlap.
A solution to resolve this is based on a different method to compare the drawing order of any two triangles, instead of just distance. It looks at whether any vertex of one triangle is "inside of" the other triangle from the perspective of the viewer. If so, it determines whether that vertex is in front of or behind the other triangle and then orders the triangles the same way. If not, the order doesn't matter because neither triangle obstructs the other. This 2-triangle comparison is then used as the comparison operator for a sorting algorithm that sorts all triangles.
This works if there are no cycles in your triangle order. It is possible that part of triangle A is in front of part of triangle B, part of B is in front of part of C, and part of C is in front of A. For example, in the bowtie example, add a third triangle that overlaps part of the right side and part of the left, but does not overlap the center of the bowtie. In this case, the left triangle blocks the right, right blocks third, and third blocks left, so there is no ordering that will work. A more sophisticated method is required than just choosing an order to draw the triangles. Depth buffers would work if you switch to drawing pixels, or you could divide triangles into smaller ones that break the cycles in order to stay with the draw_triangle interface.