2 votes

C++ Constructeur de copie d'un objet possédant un descripteur de fichier POSIX

J'ai besoin de mettre des objets C++ possédant des descripteurs de fichiers POSIX dans un vecteur. J'ai un vecteur de chemins de fichiers que j'utilise pour créer mes objets. Voici mon code :

main.cpp

std::vector<MightyObject> mightyObjects;
std::vector<const char*> paths = {"awesomePath1", "awesomePath2"};
for (std::vector<const char*>::iterator it = paths.begin(); it != paths.end(); ++it)
{
    mightyObjects.emplace_back(MightyObject(*it));
}

MightyObject.cpp

MightyObject::MightyObject(const char* path)
{
   this->fd = open(path, O_RDWR | O_NONBLOCK);
}

MightyObject::~MightyObject()
{
    close(this.fd);
}

MightyObject::MightyObject(const MightyObject& obj)
{
    this->fd = dup(obj.fd);
}

MightyObject& MightyObject::operator=(const MightyObject& other)
{
    this->fd = dup(other.fd);
    return *this;
}

Dans mightyObjects, j'ai des objets avec de mauvais descripteurs de fichiers...

Qu'est-ce que je fais de mal ?

6voto

user4815162342 Points 27348

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 .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X