Здесь:
AnimalPtr operator[](int index) {
return animals[index];
}
Вы возвращаетесь по значению, тогда копии назначается новое значение. Предполагается, что вы должны вернуть ссылку:
AnimalPtr& operator[](int index) {
return animals[index];
}
Также вы, вероятно, намеревались использовать make_shared
вместо make_unique
во всех случаях.