Je veux avoir une classe avec une variable membre de pointeur. Ce pointeur doit pointer vers un objet qui peut être alloué par pile ou par tas. Cependant, ce pointeur ne doit pas avoir de propriété. En d'autres termes, aucune suppression ne doit être appelée du tout lorsque le pointeur est hors de portée. Je pense qu'un pointeur brut pourrait résoudre le problème ... Cependant, je ne suis pas sûr qu'il existe une meilleure approche C ++ 11 que des pointeurs bruts?

Exemple:

class foo{
public:
    bar* pntr
};

int main(){
    bar a;
    foo b;
    b.pntr=&a;
}
14
Humam Helfawi 2 janv. 2016 à 19:37

5 réponses

Meilleure réponse

Les pointeurs bruts sont parfaitement bien ici. C ++ 11 n'a pas d'autre pointeur intelligent «stupide» qui traite des objets non propriétaires, vous ne pouvez donc pas utiliser de pointeurs intelligents C ++ 11. Il existe une proposition pour un pointeur intelligent "stupide" pour les objets non possédés:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4282.pdf

Déjà implémenté expérimentalement en tant que std::experimental::observer_ptr (merci @ T.C. pour l'indice).

Une autre alternative consiste à utiliser un pointeur intelligent avec un suppresseur personnalisé qui ne fait rien:

#include <memory>

int main()
{
    int a{42};

    auto no_op = [](int*){};
    std::unique_ptr<int, decltype(no_op)> up(&a, no_op);
}

Ou, comme mentionné par @ T.C. dans le commentaire, un std::reference_wrapper.

Comme mentionné par @Lightness Races in Orbit, une std::weak_ptr peut également être une solution, car ce dernier est également un pointeur intelligent non propriétaire. Cependant, un std::weak_ptr ne peut être construit qu'à partir d'un std::shared_ptr ou d'un autre {{ X3}}. Un inconvénient sérieux est que le std::shared_ptr est un objet "lourd" (à cause du mécanisme de comptage de référence interne). Notez que même dans ce cas, le std::shared_ptr doit avoir un suppresseur personnalisé trivial, sinon il corrompt la pile pour les pointeurs vers des variables automatiques.

20
vsoftco 2 janv. 2016 à 21:12

L'utilisation d'un pointeur brut est parfaitement acceptable ici car vous n'avez pas l'intention de laisser le pointeur s'approprier la ressource pointée.

3
Snps 2 janv. 2016 à 16:43

Si par "meilleure approche" vous entendez "approche plus sûre", alors oui, j'ai implémenté un pointeur intelligent "non propriétaire" ici: https://github.com/duneroadrunner/SaferCPlusPlus. (Alerte de prise sans vergogne, mais je pense que c'est pertinent ici.) Donc, votre code ressemblerait à ceci:

#include "mseregistered.h"
...

class foo{
public:
    mse::TRegisteredPointer<bar> pntr;
};

int main(){
    mse::TRegisteredObj<bar> a;
    foo b;
    b.pntr=&a;
}

TRegisteredPointer est "plus intelligent" que les pointeurs bruts en ce sens qu'il sait quand la cible est détruite. Par exemple:

int main(){
    foo b;
    bar c;
    {
        mse::TRegisteredObj<bar> a;
        b.pntr = &a;
        c = *(b.pntr);
    }
    try {
        c = *(b.pntr);
    } catch(...) {
        // b.pntr "knows" that the object it was pointing to has been deleted so it throws an exception. 
    };
}

TRegisteredPointer a généralement un coût de performance inférieur à celui de std :: shared_ptr. Beaucoup plus bas lorsque vous avez la possibilité d'allouer l'objet cible sur la pile. C'est encore assez récent et pas encore bien documenté, mais la bibliothèque comprend des exemples commentés de son utilisation (dans le fichier "msetl_example.cpp", la moitié inférieure).

La bibliothèque fournit également TRegisteredPointerForLegacy, qui est un peu plus lent que TRegisteredPointer mais peut être utilisé comme substitut instantané des pointeurs bruts dans presque toutes les situations. (En particulier, il peut être utilisé avant que le type de cible ne soit complètement défini, ce qui n'est pas le cas avec TRegisteredPointer.)

En ce qui concerne le sentiment de votre question, je pense que c'est valable. A présent, les programmeurs C ++ devraient au moins avoir la possibilité d'éviter tout risque inutile d'accès à la mémoire non valide. Les pointeurs bruts peuvent également être une option valable, mais je pense que cela dépend du contexte. S'il s'agit d'un logiciel complexe où la sécurité est plus importante que les performances, une alternative plus sûre pourrait être meilleure.

0
Noah 26 janv. 2016 à 19:57

Le problème avec un pointeur brut est qu'il n'y a aucun moyen de savoir s'il pointe toujours vers un objet valide. Heureusement, std::shared_ptr dispose d'un constructeur d'alias que vous pouvez utilisez pour créer efficacement un std::weak_ptr sur un membre de classe avec une durée de stockage automatique. Exemple:

#include <iostream>
#include <memory>

using namespace std;

struct A {
    int x;
};

void PrintValue(weak_ptr<int> wp) {
    if (auto sp = wp.lock())
        cout << *sp << endl;
    else
        cout << "Object is expired." << endl;
}

int main() {

    shared_ptr<A> a(new A);
    a->x = 42;
    weak_ptr<int> wpInt (shared_ptr<int>(a, &a->x));

    PrintValue(wpInt);
    a.reset();  //a->x has been destroyed, wpInt no longer points to a valid int
    PrintValue(wpInt);

    return 0;
}

Tirages:

42

L'objet a expiré.

Le principal avantage de cette approche est que weak_ptr n'empêche pas l'objet de sortir de la portée et d'être supprimé, mais en même temps, il peut détecter en toute sécurité quand l'objet n'est plus valide. Les inconvénients sont l'augmentation de la surcharge du pointeur intelligent et le fait que vous ayez finalement besoin d'un shared_ptr sur un objet. C'est à dire. vous ne pouvez pas faire cela exclusivement avec des objets alloués sur la pile.

0
Community 20 juin 2020 à 09:12

Allouez simplement l'objet dynamiquement et utilisez un shared_ptr. Oui, cela supprimera réellement la chose, mais seulement si c'est la dernière avec une référence. De plus, cela empêche également les autres de le supprimer. C'est exactement la bonne chose à faire, à la fois pour éviter les fuites de mémoire et les pointeurs suspendus. Consultez également le weap_ptr associé, que vous pourriez peut-être utiliser à votre avantage, si les exigences de durée de vie pour la pointee sont différentes.

-3
Ulrich Eckhardt 2 janv. 2016 à 17:49