2016-03-06 1 views
2

Quelqu'un peut-il m'expliquer pourquoi l'accident ici?Crash avec shared_ptr

#include <memory> 
#include <functional> 

struct Teacher : std::enable_shared_from_this<Teacher> { 
    struct Timetable; 
    std::shared_ptr<Timetable> timetable; 
    Teacher (int n) : timetable(std::make_shared<Timetable>(*this, n)) {} 
}; 

struct Period { 
    std::shared_ptr<Teacher> teacher; 
    Period (const std::shared_ptr<Teacher>& t) : teacher(t) {} 
}; 

struct Teacher::Timetable { 
    Teacher& teacher; 
    std::shared_ptr<Period> homeForm; 
    Timetable (Teacher& t, int n) : teacher(t), // Assume something is done with n. 
     homeForm(std::make_shared<Period>(teacher.shared_from_this())) {} // Crashes. 
//  homeForm(std::make_shared<Period>(std::shared_ptr<Teacher>(&teacher))) {} // Also crashes. 
}; 

int main() { 
    std::shared_ptr<Teacher> teacher = std::make_shared<Teacher>(3); 
} 

est-ce pas ici depuis teacher.shared_from_this() admis std::shared_ptr<Teacher> teacher est un shared_ptr déjà? Si non, comment initialiser homeForm correctement?

Répondre

2

Le problème est que votre code appelle shared_from_this avant que le std::shared_ptr<Teacher> soit entièrement construit. Il est en quelque sorte logique que le sous-objet Teacher doive être construit avant que le pointeur intelligent soit entièrement construit.

Si vous modifiez le code comme celui-ci,

struct Teacher : std::enable_shared_from_this<Teacher> { 
    struct Timetable; 
    std::shared_ptr<Timetable> timetable; 
    Teacher() {} 
    void init(int n) { this->timetable = std::make_shared<Timetable>(*this, n); } 
}; 

// Everything else unchanged 

int main() { 
    std::shared_ptr<Teacher> teacher = std::make_shared<Teacher>(); 
    teacher->init(3); 
} 

il fonctionnera bien.

Notez que je ne recommande pas cela comme un refactoring. Les constructeurs doivent entièrement initialiser les objets autant que possible. En regardant votre code, il me semble que vous pourriez envisager de le restructurer un peu plus radicalement. Avez-vous vraiment besoin de tous ces pointeurs partagés de références croisées?

+1

Fondamentalement, c'est le constructeur 'shared_ptr' qui définit le' weak_ptr' dans la base 'enable_shared_from_this'. Vous avez donc besoin de construire le 'shared_ptr ' - pas seulement le 'Teacher'. – Barry

+0

Merci. Mais dans mon programme actuel, le constructeur du professeur a des arguments qui doivent être passés au constructeur Teacher :: Timetable. Ce qui signifie que init doit recevoir ces arguments. J'ai mis à jour ma question. Est-ce que dupliquer ces arguments dans main() est le seul moyen? Ou stocker ces arguments dans 'Teacher' et les passer ensuite à' init', même s'ils ne sont que temporaires? – prestokeys

+0

@prestokeys Je ne vois pas pourquoi vous devriez les passer au constructeur. Mais je répète que je ne * promets * pas * l'utilisation d'une fonction "init" ou de ce style de codage en général. – 5gon12eder