Question

Comment écrire un getter qui ne peut pas être supprimé? Je veux posséder les variables et ne pas les partager. lire ici et là je me suis dit que peu importe ce que je retourne la mémoire peut être libéré

mais je le définir, est-ce vrai?

références, pointeurs const, peu importe quoi, la fonction qui appelle le getter peut le supprimer et ma variable privée ne serait pas annulé mais avec une mémoire brisée, non?

Je voudrais développer un getter où je peux retourner ma variable privée et assurez-vous que le callee ne peut pas le supprimer ...

Je crains que, tout en utilisant la variable privée, l'a détruite callee puis il se bloque loin mon programm sur ma prochaine tentative interne de l'utiliser

dans une première tentative, je ne voudrais pas utiliser boost, comme je suis en train d'apprendre le plus de ce projet, coup de pouce serait utilisé sinon inverse ou si l'inverse est trop complexe / bien-travail

Merci,

Joe

Mon autre question n'a pas été vraiment concentré, donc je l'ai fait à nouveau, ce ne est pas un problème de demande des choses ici, non? =]

Était-ce utile?

La solution

Cela dépend de ce que vous voulez dire. Chaque fois que vous avez un pointeur, il est possible pour appeler delete dessus.

Et si vous avez une référence, vous pouvez prendre l'adresse de celui-ci, ce qui vous donne un pointeur

Quoi qu'il en soit, si vous avez cette classe, par exemple:

class X {
  int getByVal() { return i; } // returns a copy of i
  int& getByRef() { return i; } // returns a reference to i
private:
  int i;
};

je, en tant qu'utilisateur de votre classe, ne dispose pas d'un moyen de supprimer vos données évident . Je peux faire ce qui suit:

X x;
int j = x.getByVal();
int& k = x.getByRef();
j = 42; // doesn't affect x.i because we returned a copy
k = 42; // sets x.i to 42, because k is a reference

Et il n'y a aucun moyen évident pour moi de supprimer le membre de la classe. Bien sûr, je peut faire ceci:

delete &j;
delete &k;

(et bien sûr, aucune de ces feraient quelque chose de significatif, mais ils ne voulaient compiler) mais je ne le ferais pas par hasard. Si vous ne retournez pas un pointeur, il est assez clair que je ne suis pas censé prendre possession des données.

« Protégez votre code contre Murphy, pas Machiavel » est généralement une bonne règle de base. Vous ne pouvez pas empêcher les gens de ruiner votre code si elles essaient . Tout ce que vous devriez vous inquiéter les empêche de le faire accidentellement.

Modifier En réponse à votre commentaire sous la question:

  

comme je le disais, j'apprends ... Des copies font penser que le doit libérer la callee mémoire de la variable de retour, ce qui est plus de mal à l'callee (même pensé qu'il est moi = p), donc je ne parler de concepts, mais le easyness de l'écriture ... et encore, je suis novice sur ce genre de choses mémoire. Je développais en C #, PHP etc. J'utilisé pour développer en C il y a longtemps quand j'apprenais avec CircleMUD

Non, les copies ne doivent pas être supprimés manuellement. Les variables locales sont automatiquement supprimées quand ils sont hors de portée. Ainsi, dans l'exemple ci-dessus, j est une copie du membre de la classe i. Lorsque la fonction d'appel retourne, j sera automatiquement supprimé.

L'espoir qui aide. Les règles de vie variables en C ++ ne sont pas très compliqué, mais il est extrêmement important de les obtenir droit comme beaucoup de code dépend.

void foo()
{
  int i = 0; // allocate a local (on the stack) int, and initialize it to 0
  int* p = new int(1); // allocate an int on the heap, and initialize it to 1
  int j = i; // create a *copy* of i. Now we have two ints on the stack
  int k = *p; // create a copy of the int pointed to by p. k is also on the stack, so even though it was copied from a heap-allocated variable, k does not have to be manually deleted
  int* q = p; // create a copy of p. q is not a separate pointer, which points to the *same* heap-allocated integer.
}

dans l'exemple ci-dessus, toutes les copies sont nettoyées automatiquement lors du retour de foo. La seule chose que nous devons faire est manuellement pour supprimer le nombre entier, nous avons alloué sur le tas. Les deux points de p et q à elle, mais il faut que supprimer l'objet une fois. Mais i, j, k, p et q sont toutes les variables locales, déclarées sur la pile. Chacun d'entre eux sont nettoyés lorsque la fonction retourne. Pour les types primitifs (tels que ints ainsi que des pointeurs), rien n'a vraiment arriver (ils n'ont pas Destructeurs). Quand ils sont hors de portée, ils disparaissent juste -. Même si elles ont fait quelque chose d'important, comme un objet alloué-tas comme notre entier

Pour les objets non-POD, quand ils sont hors de portée, leurs destructeurs sont appelés, ils deviennent trop bien nettoyés, par eux-mêmes. Donc, même si nous avions utilisé un type plus complexe que int, le ci-dessus aurait travaillé très bien. Nous pouvons encore copier des objets non-POD et de les transmettre par valeur.

J'espère que les choses claires aide un peu.

Autres conseils

Eh bien, la meilleure façon de le faire est de renvoyer une copie de votre objet en valeur:

MyObject GetMyObject() const {return _myObject;}

Ensuite, l'appelant peut faire tout ce qu'il veut avec sa copie, et il ne vous affectera pas.

Bien sûr, cela n'encourir les frais généraux de copie de l'objet ... si c'est important ou non dépend de la complexité de l'objet est (et donc combien il est coûteux de le copier).

La meilleure chose est de retourner une référence const lui:

const MyObject & GetMyObject() const {return _myObject;}

Cela donnera l'appelle une référence à l'objet, qui peut techniquement être supprimé, mais ne sera généralement pas (il est supposé que la propriété ne passe lors du retour d'une référence).

La dernière chose que vous pouvez faire est d'utiliser le comptage de référence pour renvoyer une référence à l'objet. Dans ce cas, personne ne doit jamais supprimer l'objet, étant donné que l'objet sera automatiquement supprimé lorsque la dernière référence disparaît. Consultez pour plus de détails sur cette classe shared_ptr de boost; Je recommande fortement le comptage de référence comme un moyen de gérer l'allocation de mémoire en C ++, car il automatise l'écart de 99% des erreurs potentielles programmeurs font dans la gestion de la mémoire.

En C ++, il n'y a rien que vous pouvez faire pour empêcher l'appelant de plantage de votre programme. Période.

Je suggère simplement retourner une référence. Si l'appelant va et prend l'adresse de cela et passe à delete, ils demandent des ennuis -. Et si elles sont cette intention sur les choses de rupture, il n'y a pas grand-chose que vous pouvez faire pour les arrêter

Vous pouvez utiliser des pointeurs faibles pour cela. pointeurs faibles se rapportent à une ressource appartenant à un pointeur intelligent partage sans ajouter à son compte de référence. (Cependant, aussi longtemps que les utilisateurs peuvent obtenir un pointeur nu à partir d'un pointeur intelligent - et sans cela, il serait seulement smart , mais pas pointeur plus -, ils peuvent invoquer delete sur cette Mais c'est OK... Si les gens veulent planter leur code, ils trouveront toujours des moyens de le faire voir votre objectif dans la prévention de Murphy de faire son travail, et non Macchiavelli

Bien sûr, vous pouvez tout aussi bien revenir une référence. (La même mise en garde comme applique ci-dessus.)

Si vos objets ne coûtent pas cher à copier, vous pouvez également retourner une copie. (Et il est, syntqactically, toujours possible de transmettre l'adresse de la copie à delete.)

Si vous revenez en valeur, l'appelant pas accès à votre membre interne.

Une solution vraiment ad hoc pourrait être surcharger l'opérateur et d'en supprimer (et peut-être nouveau [] / supprimer []), ce qui rend l'opérateur de suppression d'un accès privé et d'accorder uniquement à la classe propriétaire:

#include <memory>

class Y
{
private:
    void* operator new(size_t size) { return new char[size]; }
    void operator delete(void* p) { delete [] static_cast<char*>(p); }
    friend class X;
};

class X
{
    Y* p;
    X(const X& x);
    const X& operator=(const X& x);
public:
    X(): p(new Y()) {}
    ~X() { 
        delete p;  //OK here, X is a friend
    }
    const Y* get() const { return p; }
};

int main()
{
    X x;
    const Y* p = x.get();
    delete p;  //error here: operator delete is private
}

Cependant, tant que vous ne retournez pas un pointeur nu où une erreur peut être imaginable, si vous deviez retourner un pointeur intelligent, et l'appelant a quand même décidé de libérer le pointeur managé, tout ce qui s'ensuit sera leur problème . Quasiment chaque fois que vous voyez un appel à supprimer, vous sauriez ce doit être une erreur.

Avez-vous pensé à trouver des gens qui écrivent du code qui supprime d'autres variables du module, et les pistolage puce ou quelque chose comme ça?

Sérieusement, si vos collègues sont absolument déterminés à briser les choses, il n'y a vraiment pas grand-chose que vous pouvez faire à ce sujet (sauf les feu sur place, si vous êtes le patron). Heck, il n'y a aucune garantie que ce que vous passez à quelque chose qui a été séparément alloué, et si l'appelant utilise delete sur une adresse au hasard on ne sait pas ce qui se passera (sauf qu'une certaine forme de corruption du tas est presque certain).

Il n'y a pas de construction langage de programmation ou langage de programmation pour cette question, ce qui vous épargnera des collègues comme ça. « Contre la bêtise les dieux eux-mêmes soutiennent en vain. »

Je ne sais pas si c'est ce que vous recherchez et il dépend aussi beaucoup d'efforts que vous avez vraiment besoin de prendre, mais vous pouvez toujours utiliser le Pimpl idiome .

Enveloppez le membre que vous ne voulez pas exposer et juste passer des poignées à elle. Les poignées ne sont que des emballages légers qui peuvent être allègrement passés autour de la valeur, chaque poignée simplement des points à la même pièce unique sous-jacente de données seulement votre code interne peut réellement créer et détruire.

Par exemple,

class Interface
{
public:
    Data getData() const { return Data( m_data ); }

private:
    DataImpl* m_data;
};

class Data
{
public:
    // Just use compiler-synthesised copy ctor, assignment and dtor

    // Declare as many forwarding methods to impl as required
    // ...

private:
    friend class Interface;
    Data( DataImpl* d ) : m_impl( d ) {}
    DataImpl*const m_impl;
};

L'exemple simple ici est naïf car il ne remet pas Data poignées existantes lorsque le DataImpl est finalement détruit et ils sont laissés avec des pointeurs rassis. Ceci peut être résolu avec plus d'efforts, mais encore une fois que vous êtes parti avec la question de savoir si elle vaut vraiment la peine.

Si vous avez un objet qui prend la propriété (Une banque prend un compte (parvins je sais)).
Mais les gens veulent avoir accès au compte, mais vous ne voulez pas les supprimer.

class Bank
{
    public:
        // use auto_ptr to indicate transfer of ownership to the Bank.
        void addAccount(std::auto_ptr<Account> a)
        {
            m_account = a;
        }
        //
        // getAccount() returns a reference to the object
        // Anbody using the object can NOT now delete it.
        // But they can manipulate it.
        Account&  getAccount(int accountNo)
        {
            return *m_account;
        }
    private:
        std::shared_ptr<Account>   m_account;  // In example bank only has 1 account
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top