A& is an lvalue reference, which means it can change the thing it's looking at. With
A(A& rhs)
you can call it like
int x = 10;
A a(x);
And then any changes to rhs in the constructor will change the actual variable x. And that's fine. But when you do
A a(10);
That's a problem. Because if someone changes rhs in the constructor, that means we have to "change" the number 10, and that's not really even a meaningful thing to do. 10 += 1 is nonsense in C++, for instance.
const A& is a guarantee that we aren't going to change the thing being pointed to, so it becomes safe to pass a temporary value like 10 to the function.
If we knew it was always a "small" datatype like int, we might take it by value, but we don't want to take an A as argument, since some types (like vectors) can be expensive to copy, and others (like unique_ptr) are outright impossible to copy.
Depending on your use case, you can consider using A&&, an rvalue reference. This is useful if you intend to move the value into the class you're constructing, rather than make a copy of it. You can read more about move semantics on this question, but if you're just starting out in C++, it's probably best to stay away from rvalue references. It is good to be aware that they exist, though.
bas a copy ofa, viaA b(a);) one often does not expect the logical state ofa(the object being copied) to change. Qualifying the argument of the copy constructor asconstcommunicates that is, indeed, the case. Among other things, this allows creating a temporary (an unnamed object within an expression, and copying the temporary). If it does make sense for the state ofato change, theconstcan be omitted - among other things, that does prevent copying of a temporary.