I nie czepia się o tworzenie obiektu, tylko o linie z push_back.
Polimorfizm jest mechanizmem wskaźników, nie obiektów. Kontener może przetrzymywać wskaźniki na obiekty klas mających wspólnego rodzica (który posiada chociaż jedną metode wirt. btw), ale nie bezpośrednio ich obiekty.
Działało by tak:
list<Student *> students;
MathStudent * pointer = new MathStudent;
students.push_back(pointer);
A, żeby było ładnie i bezpiecznie - powinno wyglądać tak:
list<std::unique_ptr<Student>> students;
students.push_back(std::make_unique<Student>(new MathStudent));
Swoją drogą - klasa Student powinna mieć wirtualny destruktor!