Non-primitive types can certainly be passed by value. (This is described in section 5.2.2 [expr.call] C ++ Standard.)
However, there are several reasons why this is often discouraging, especially in C ++ 03 code.
Firstly, for large objects this is less efficient (compared to passing by reference), because the data is transferred on the stack. The link will take one word on the stack, so passing any object through the stack that is more than one word will be necessarily slower.
Secondly, passing by value calls the copy constructor (or, as @templatetypedef points out, potentially a move constructor in C ++ 11). This additional processing may entail certain overhead.
Thirdly, you may have intended to modify the passed object, but by passing it in a copy (by value), any changes you make to the function will not affect the original object. Therefore, it is important to choose the right semantics (that is, whether you want to change the original). Therefore, this is a potential mistake in some circumstances.
Finally, if there is a poorly written class without a copy constructor or assignment operator, the compiler will automatically generate a default for you. This will execute a shallow copy, which can cause problems such as memory leaks. This is another good reason why it is important to implement these special methods. Full details are provided in this article:
In general, for C ++ 03 code, you usually go through the const& link if you do not intend to modify the object or the normal & link if you need to modify the object. Use a pointer if the parameter is optional.
These questions also contain some good answers and discussions, especially a discussion of the semantics of movement:
The full answer for C ++ 11 is more complicated:
Probably the best summary of which approach to use: