Thinking about this only way I could come up so far is by not using an array modifier at all and using hooks instead.
It may have some downsides and limitations like less flexible texturing and not allowing more complex shapes along the length of the curve, and it wont merge the vertex automatically, but the ends wont get deformed this way.
Model your pipe exhaust tip regularly as you did, or append it from a library, whichever way suits you best.
Instead of using an array modifier use the bezier curve bevel option directly, to give it geometry, you may even use another curve object as section for the bevel. Just make sure the exhaust tip and the section match perfectly so there are no visible seams.
Now align your cap object perfectly with the bezier curve end. That means position and rotation including curve handles so the line up perfectly. Try scaling the last curve handle to zero in all axis before hooking up.
Use the 3d cursor to snap the cap in place like Select Vertex > Shift + S Cursor to Selected, then exit edit mode select the cap and Shift + S Selection to Cursor.
Now select the Cap then the Curve (by this specific order) enter edit mode on the curve, select the last vertex you previously aligned, press Space Bar > Hook to Selected Object
This has he unexpected advantage that you can now tweak the shape of or pipe directly from object mode without ever entering edit mode in your curve.
You can use this with an array modifier, but it will not always work perfectly, depending on the exact current length of the curve it may not give an exact number of arrayed items so there will appear a gap at the end between the last arrayed object and the end cap. If you plan on applying the modifiers later you can fix it by hand.