Dipende da qual'è la tua definizione di uguaglianza. Se per te due oggetti sono uguali se al momento dell'inserimento ricevi lo stesso puntatore, non vedo molte alternative al metodo che hai descritto; ma in genere si intende che due oggetti a e b sono uguali quando a==b.
In tal caso, ti basterà scorrere la lista e confrontare gli oggetti uno ad uno usando l'operatore == (sull'oggetto, non sul puntatore - if(*(n->info)==*obj) ...). Questo funziona senza dover fare nient'altro sui tipi primitivi, mentre per le classi custom si richiede che sia ridefinito l'operatore ==.

Nota comunque che la lista non è un buon contenitore se non vuoi avere duplicati - l'inserimento diventa O(n) quando potrebbe essere O(1) (se in testa o comunque dopo un elemento che hai già).
Puoi migliorare un po' le performance mantenendo ordinata la lista, ma il caso medio resta O(n).

Per questo motivo per avere container senza duplicati normalmente si usano le hashtable (non ordinate) o gli alberi RB (ordinati).

p.s. L'istruzione T *copy = new T(*obj); considerando che l'oggetto *obj non ha un costruttore copia mi fa una shallow copy?
Sì e no; il costruttore di copia predefinito si limita a copiare i singoli campi, senza fare null'altro di particolare, per cui se hai dei puntatori questi vengono semplicemente copiati senza fare altro; d'altra parte, se i campi in questione sono oggetti - e non puntatori - verrà richiamato a sua volta il loro costruttore di copie, per cui potenzialmente può essere una deep copy.