148 votes

Utilisation de pointeurs intelligents pour les membres de la classe

Je vais avoir du mal à comprendre l'utilisation des pointeurs intelligents que les membres de la classe en C++11. J'ai lu beaucoup de choses sur les pointeurs intelligents et je pense que je dois comprendre comment unique_ptr et shared_ptr/weak_ptr de travail en général. Ce que je ne comprends pas, c'est l'utilisation réelle. Il semble que tout le monde recommande l'utilisation d' unique_ptr que le chemin à parcourir presque tout le temps. Mais comment pourrais-je mettre en place quelque chose comme ceci:

class Device {
};

class Settings {
    Device *device;
public:
    Settings(Device *device) {
        this->device = device;
    }

    Device *getDevice() {
        return device;
    }
};    

int main() {
    Device *device = new Device();
    Settings settings(device);
    // ...
    Device *myDevice = settings.getDevice();
    // do something with myDevice...
}

Disons que je voudrais remplacer les pointeurs avec des pointeurs intelligents. Un unique_ptr ne serait pas travailler en raison d' getDevice(), droite? C'est le moment lorsque j'utilise shared_ptr et weak_ptr? En aucun cas l'utilisation unique_ptr? Me semble que pour la plupart des cas shared_ptr a plus de sens, sauf si je suis à l'aide d'un pointeur dans un petit périmètre?

class Device {
};

class Settings {
    std::shared_ptr<Device> device;
public:
    Settings(std::shared_ptr<Device> device) {
        this->device = device;
    }

    std::weak_ptr<Device> getDevice() {
        return device;
    }
};

int main() {
    std::shared_ptr<Device> device(new Device());
    Settings settings(device);
    // ...
    std::weak_ptr<Device> myDevice = settings.getDevice();
    // do something with myDevice...
}

C'est que le chemin à parcourir? Merci beaucoup!

192voto

Andy Prowl Points 62121

Un unique_ptr ne serait pas travailler en raison d' getDevice(), droite?

Non, pas nécessairement. Ce qui est important ici est de déterminer la politique de propriété pour votre Device objet, c'est à dire qui va être le propriétaire de l'objet pointé par votre (smart) pointeur.

Est-ce que ça va être l'instance de l' Settings objet seul? Sera l' Device objet doivent être détruits automatiquement lorsque l' Settings objet est détruit, ou doit-il survivre à cet objet?

Dans le premier cas, std::unique_ptr est ce que vous avez besoin, car il rend l' Settings le seul (unique) propriétaire de l'objet pointé, et le seul objet qui est responsable de sa destruction.

Dans cette hypothèse, getDevice() doit retourner une simple observation de pointeur (observer les pointeurs sont des pointeurs qui ne gardent pas l'objet pointé de son vivant). La forme la plus simple d'observer pointeur est un pointeur brut:

#include <memory>

class Device {
};

class Settings {
    std::unique_ptr<Device> device;
public:
    Settings(std::unique_ptr<Device> d) {
        device = std::move(d);
    }

    Device* getDevice() {
        return device.get();
    }
};

int main() {
    std::unique_ptr<Device> device(new Device());
    Settings settings(std::move(device));
    // ...
    Device *myDevice = settings.getDevice();
    // do something with myDevice...
}

[NOTE 1: Vous demandez peut-être pourquoi je suis à l'aide de matières pointeurs ici, quand tout le monde n'arrête pas de raconter que les pointeurs sont mauvais, dangereux et dangereux. En fait, c'est un précieux avertissement, mais il est important de le mettre dans le bon contexte: les pointeurs sont mauvais quand il est utilisé pour effectuer manuel de gestion de la mémoire, c'est à dire l'allocation et la désallocation des objets par le biais new et delete. Lorsque utilisé uniquement comme un moyen de parvenir à la référence de la sémantique et de la passer autour de la non-propriété, de l'observation des pointeurs, il n'y a rien d'intrinsèquement dangereux en raw pointeurs, sauf peut-être pour le fait que l'on doit prendre soin de ne pas déréférencer un bancales pointeur. - LA FIN DE LA NOTE 1]

[NOTE 2: Comme il est apparu dans les commentaires, dans ce cas particulier où la propriété est unique et la propriété de l'objet est toujours la garantie d'être présent (c'est à dire les données internes membre device ne sera jamais nullptr), de la fonction getDevice() pourrait (et devrait peut-être) de retour d'une référence plutôt qu'un pointeur. C'est vrai, j'ai décidé de retourner un pointeur brut ici parce que je voulais que cela soit une réponse courte, que l'on peut généraliser au cas où l' device pourrait être nullptr, et de montrer que les pointeurs sont OK tant qu'on ne les utilise pas de manuel de gestion de la mémoire. - LA FIN DE LA NOTE 2]


La situation est radicalement différente, bien sûr, si votre Settings objet ne doit pas avoir la propriété exclusive de l'appareil. Cela pourrait être le cas, par exemple, si la destruction de l' Settings objet ne devrait pas impliquer la destruction de l'souligné Device objet.

C'est quelque chose que vous seul en tant que concepteur de votre programme peut dire; à partir de l'exemple que vous fournissez, il est difficile pour moi de dire si c'est le cas ou pas.

Pour vous aider à comprendre, vous pouvez vous demander s'il existe d'autres objets en dehors de Settings qui ont le droit de conserver l' Device objet vivant, tant qu'ils détiennent un pointeur vers elle, au lieu d'être des observateurs passifs. Si c'est effectivement le cas, alors vous avez besoin d'une propriété partagée de la politique, qui est ce que l' std::shared_ptr offre:

#include <memory>

class Device {
};

class Settings {
    std::shared_ptr<Device> device;
public:
    Settings(std::shared_ptr<Device> const& d) {
        device = d;
    }

    std::shared_ptr<Device> getDevice() {
        return device;
    }
};

int main() {
    std::shared_ptr<Device> device = std::make_shared<Device>();
    Settings settings(device);
    // ...
    std::shared_ptr<Device> myDevice = settings.getDevice();
    // do something with myDevice...
}

Avis, weak_ptr est une observation de pointeur, pas un propriétaire de pointeur - en d'autres termes, il ne tient pas de l'objet pointé est vivante que si tous les autres de posséder des pointeurs vers l'objet pointé hors de portée.

L'avantage de l' weak_ptr plus régulière d'un pointeur brut, c'est que vous pouvez sans risque dire qu' weak_ptr est bancale ou pas (c'est à dire qu'il pointe vers un objet valide, ou si l'objet à l'origine, a souligné a été détruit). Cela peut être fait par l'appel de la expired() des membres de la fonction sur l' weak_ptr objet.

0voto

Naszta Points 4322
class Device {
};

class Settings {
    std::shared_ptr<Device> device;
public:
    Settings(const std::shared_ptr<Device>& device) : device(device) {

    }

    const std::shared_ptr<Device>& getDevice() {
        return device;
    }
};

int main()
{
    std::shared_ptr<Device> device(new Device());
    Settings settings(device);
    // ...
    std::shared_ptr<Device> myDevice(settings.getDevice());
    // do something with myDevice...
    return 0;
}

week_ptr est utilisé uniquement pour les boucles de référence. Le graphe de dépendance doit être acyclicdirected graphique. En commun des pointeurs, il y a 2 nombre de références: 1 shared_ptrs, et 1 pour tous les pointeurs (shared_ptr et weak_ptr). Lorsque tous shared_ptrs sont supprimés, le lien est supprimé. Lorsque le pointeur est nécessaire d' weak_ptr, lock doit être utilisé pour obtenir le pointeur, si elle existe.

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