0
votes

Comment puis-je supprimer tous les pointeurs vers la même adresse? C ++

J'essaye de réaliser un pointeur intelligent par moi-même. Je sais que je peux utiliser des pointeurs intelligents au lieu de cela, mais j'essaie de le faire uniquement pour comprendre la structure des pointeurs intelligents.

Ð ¢ e problème est le suivant lorsque mon pointeur intelligent a commencé à appeler le destructeur, cela vérifie si mon pointeur n'est pas nullptr puis s'il est vrai, cela supprimera ptr.

Après cela, lorsque le destructeur a de nouveau appelé CastS, je reçois une exception car le destructeur tente de supprimer un élément déjà supprimé et mon instruction if pour la deuxième fois ne fonctionne pas (comme je m'y attendais) car après la suppression d'un élément, l'adresse change et le pointeur n'est plus nul.

Comment puis-je améliorer ce code et comment ne pas supprimer deux fois le pointeur déjà supprimé?

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <memory>

using std::cout;
using std::endl;

template<typename T>
class Smart_Pointer
{
private:
    T* ptr;
public:
    Smart_Pointer(T* ptr);
    ~Smart_Pointer();
    T& operator*();
};
template<typename T>
Smart_Pointer<T>::Smart_Pointer(T* ptr)
{
    this->ptr = ptr;
}

template<typename T>
Smart_Pointer<T>::~Smart_Pointer()
{
    if (ptr != nullptr)
    {
        delete ptr;
        ptr = nullptr;
        
    }

}

template<typename T>
T& Smart_Pointer<T>::operator*()
{
    return *ptr;
}

int main()
{
    Smart_Pointer<int> castS(new int(10));
    Smart_Pointer<int> castS2 = castS;
}


3 commentaires

Ce n'est pas ainsi que fonctionnent les pointeurs intelligents.


Cela ne répond pas à la question, mais delete ptr; mot très bien si ptr est un pointeur nul; il n'y a pas besoin de if (ptr != nullptr) . Et définir ptr = nullptr; après la suppression est inutile, car l'objet est en cours de destruction et ptr n'existera plus.


Smart_Pointer(Smart_Pointer const&) = delete; car le constructeur de copie généré par le compilateur ne fonctionnera pas. Et Smart_Pointer& operator=(Smart_Pointer const&) = delete; pour l'opérateur d'affectation, pour les mêmes raisons.


4 Réponses :


0
votes

Si vous essayez d'émuler le comportement de unique_ptr, cela est résolu simplement en n'autorisant pas la copie. Si vous supprimez le constructeur de copie, deux pointeurs intelligents ne peuvent pas pointer vers la même adresse en même temps. Vous écrivez simplement:

SmartPtr(SmartPtr&& other) {
    ptr = std::exchange(other.ptr, nullptr);
}

Cependant, si vous faites cela, vous voudrez peut-être un moyen de transférer la propriété, il serait donc bien d'implémenter un constructeur de déplacement:

SmartPtr(const SmartPtr&) = delete;

Ou quelque chose comme ça. Si vous voulez vraiment permettre à deux pointeurs intelligents de pointer vers la même adresse, vous avez besoin d'un moyen de décider lequel va supprimer le ptr, généralement le dernier qui sort du champ d'application. La façon dont cela est fait dans le standard (par exemple dans shared_ptr) est de définir une structure partagée entre toutes les instances de la classe, mais c'est probablement hors de portée de cette réponse.


3 commentaires

Je l'ai corrigé. Ce n'est pas faux cependant, juste différent de la norme


Qu'entendez-vous par «différent de la norme»? C'est UB parce que vous lisez une variable non initialisée et que la delete devrait se bloquer à moins que le pointeur ne soit nul.


Je vois, tu as raison. Je pensais déménager.



2
votes

Smart Pointer est un terme générique. Pour la bibliothèque std, il décrit unique_ptr , shared_ptr et weak_ptr .

Si vous souhaitez implémenter un ptr unique, vous devez vous assurer qu'un seul ptr unique possède le pointeur brut, vous devez donc supprimer le constructeur de copie et l' opérateur d'affectation de copie . Pour pouvoir transférer la propriété entre vos pointeurs uniques, vous devez fournir un constructeur de déplacement et un opérateur d'attribution de déplacement de manière à ce que la propriété soit transférée.

Si vous souhaitez implémenter un ptr partagé, vous devez implémenter le comptage de références.

Comment puis-je supprimer tous les pointeurs vers la même adresse? C ++

C'est quelque chose que vous ne voulez pas faire, vous voulez garder l'objet géré en vie tant qu'il y a au moins un pointeur partagé possédant cet objet géré.

La règle de trois / cinq / zéro :

Règle de trois : si une classe nécessite un destructeur défini par l'utilisateur, un constructeur de copie défini par l'utilisateur ou un opérateur d'affectation de copie défini par l'utilisateur, elle requiert presque certainement les trois.

Règle de cinq : Étant donné que la présence d'un destructeur, d'un constructeur de copie ou d'un opérateur d'affectation de copie défini par l'utilisateur empêche la définition implicite du constructeur de déplacement et de l'opérateur d'affectation de déplacement, toute classe pour laquelle la sémantique de déplacement est souhaitable doit déclarer les cinq fonctions spéciales des membres:


0 commentaires

1
votes

Comment puis-je supprimer tous les pointeurs vers la même adresse? C ++

Vous ne pouvez probablement pas le faire de manière fiable et automatique. Soyez conscient du théorème de Rice , et en savoir plus sur la programmation en C ++ , puis consultez cette référence C ++ . Comprenez que les pointeurs organisent votre espace d'adressage virtuel comme un graphe orienté qui évolue pendant l'exécution de votre programme.

Vous souhaitez peut-être effacer tous les pointeurs vers la même adresse.

Ensuite, en savoir plus sur Garbage Collection .

Par exemple, lisez le manuel du GC .

Pensez à utiliser un outil d'analyse statique sur votre code source C ++, par exemple l' analyseur statique Clang .

Envisagez également de générer votre code C ++ (comme le fait SWIG ou GNU bison ). Vous pouvez coder votre générateur de code C ++ (par exemple en utilisant GPP ou GNU m4 , ou votre propre générateur de fichiers C ++) pour faciliter la gestion de vos pointeurs.

Lisez aussi n3337 (un projet de norme C ++) et la documentation de votre compilateur C ++ (peut-être GCC ).

Sachez que le comptage de références a des inconvénients (par exemple, il n'est pas compatible avec le multi-thread).

Étudiez pour vous inspirer le code source des programmes open source C ++ existants (par exemple sur github ), tels que Fish , Qt , RefPerSys , GCC , Clang , ANTLR . Pensez à contribuer à l'un d'entre eux.


0 commentaires

0
votes

Comment puis-je supprimer tous les pointeurs vers la même adresse?

Le premier problème est que vous ne savez pas combien de points correspondent à la même adresse.

Cela peut être résolu de plusieurs manières.

  1. En utilisant un bloc de contrôle (comme std :: shared_ptr), tous les pointeurs intelligents pointent vers un bloc de contrôle qui pointe vers l'objet réel et possède un compteur.
  2. En utilisant un compteur intrusif dans le pointeur sur objet, héritez-le ou l'objet doit être hérité par le compteur.
  3. Utilisation d'un compteur gratuit externe.
  4. Analysez toute la mémoire pour voir si quelque chose pointe aussi cette adresse (Garbage collection, GC).

Le compteur doit être atomique si vous avez l'intention de faire du multi-threading.

L'implémentation d'un compteur libre externe a l'énorme avantage que vous n'avez pas l'indirection de 1. et que vous n'avez pas l'intrusivité de 2 ni la complexité de GC.

Code non testé

template<typename T>
Smart_Pointer<T>::~Smart_Pointer() {
  if (ptr != nullptr) {
    if (--extro_count[ptr] == 0) {
      extro_count.erase(ptr);
      delete ptr;
      ptr = nullptr;
  }
}

Vous devez ensuite implémenter la règle de 3 ou la règle de 5 en fonction de votre niveau d'avancement.

std::unordered_map<void *, std::atomic_int> extro_count;

Je laisse la mise en œuvre des autres au PO.

Ceci est toujours très dangereux dans le code thread à moins que vous ne soyez prudent.


0 commentaires