Le code tel qu'il est présenté devrait contenir des descripteurs de fichiers corrects, même s'il y aura des fuites de descripteurs lors des affectations. Pour le corriger, vous devez le changer en :
- Corriger la fuite dans l'opérateur d'affectation ;
- Gérer l'auto-affectation ;
- Mettre en œuvre un Constructeur de mouvement pour optimiser les mouvements (et parce que cette classe est un exemple de manuel des avantages de la construction de mouvements) ;
- Gérer les erreurs.
Par exemple (non testé) :
static int safe_dup(int fd) {
int copy = dup(fd);
if (copy < 0)
throw std::runtime_error(strerror(errno));
return copy;
}
MightyObject::MightyObject(const char* path) {
this->fd = open(path, O_RDWR | O_NONBLOCK);
if (this->fd == -1)
throw std::runtime_error(strerror(errno));
}
MightyObject::~MightyObject() {
if (this->fd != -1)
close(this->fd);
}
MightyObject::MightyObject(const MightyObject& other) {
this->fd = safe_dup(other.fd);
}
MightyObject& MightyObject::operator=(const MightyObject& other) {
if (this != &other) {
close(this->fd);
this->fd = safe_dup(other.fd);
}
return *this;
}
MightyObject::MightyObject(MightyObject&& other) {
// "move" file descriptor from OTHER to this: no duping is needed,
// we just take the descriptor and set the one in OTHER to -1, so
// it doesn't get closed by OTHER's destructor.
this->fd = other.fd;
other.fd = -1;
}
MightyObject& MightyObject::operator=(MightyObject&& other) {
// move assignment operator
close(this->fd);
this->fd = other.fd;
other.fd = -1;
}
Une fois que vous avez compris la sémantique du déplacement, vous pouvez réduire la répétition du code entre les opérateurs en déployant la fonction idiome "copy and swap .
Notez que ce qui précède doit être compris comme un exercice de codage et de compréhension. En production, vous ne voudrez probablement pas allouer un nouveau descripteur de fichier chaque fois que votre objet est copié. Une meilleure conception consisterait à faire en sorte que le descripteur de fichier soit déplacé uniquement et à mettre en œuvre la méthode suivante MightyObject
comme std::shared_ptr<Handle>
. Cela évitera complètement dup
et de manipuler le constructeur de copie, l'opérateur d'affectation, etc., car tous ces éléments seront gérés par shared_ptr
.