Question

Je sais que la mémoire à l'aide de nouveaux ventilés entre, obtient son espace en tas, et nous avons donc besoin de le supprimer avant la fin du programme, afin d'éviter la fuite de mémoire.

look Let à ce programme ...

Case 1:

char *MyData = new char[20];
_tcscpy(MyData,"Value");
.
.
.
delete[] MyData; MyData = NULL;


Case 2:
char *MyData = new char[20];
MyData = "Value";
.
.
.
delete[] MyData; MyData = NULL;

Dans le cas 2, au lieu de l'attribution de la valeur au segment de mémoire, il se dirige vers un littéral de chaîne.

Maintenant, quand nous faisons une suppression, il se briserait, comme on s'y attendait, car il ne cherche pas à supprimer une mémoire de tas. Y at-il un moyen de savoir où le pointeur pointe vers tas ou la pile?

Par ce programmeur

  • ne tentera pas de supprimer toute la mémoire de la pile
  • Il peut enquêter sur pourquoi cette Ponter, qui pointait vers une mémoire de tas d'abord, est fait de se référer littéraux locaux? Qu'est-il arrivé à la mémoire du tas au milieu? Est-elle fait le point par un autre pointeur et supprimer ailleurs et tout cela?
Était-ce utile?

La solution

Y at-il un moyen de savoir où le pointeur pointe vers tas ou la pile?

Vous pouvez savoir ce que si vous vous en souvenez au moment de l'attribution. Ce que vous faites dans ce cas est de stocker vos pointeurs dans les classes intelligentes de pointeur et le stocker dans le code de classe.

Si vous utilisez boost::shared_ptr comme un exemple, vous pouvez faire ceci:

template<typename T> void no_delete(T* ptr) { /* do nothing here */ }

class YourDataType; // defined elsewhere
boost::shared_ptr<YourDataType> heap_ptr(new YourDataType()); // delete at scope end

YourDataType  stackData;
boost::shared_ptr<YourDataType> stack_ptr(&stackData, &no_delete); // never deleted

Autres conseils

Dès que vous avez besoin que les connaissances que vous avez déjà perdu. Pourquoi? Parce qu'alors, même si vous omettez la mauvaise suppression [], vous avez encore une fuite de mémoire.

Celui qui crée la mémoire doit toujours être celui qui le supprime. Si, à une occasion un pointeur peut se perdre (ou écrasées), alors vous devez garder une copie pour la bonne suppression.

Il est impossible dans la norme C ++ de déterminer si un pointeur vers la mémoire allouée dynamiquement ou non. Et notez que les littéraux de chaîne ne sont pas attribués sur la pile.

Comme la plupart des utilisateurs ont dit ici il n'y a aucun moyen standard pour découvrir quelle mémoire vous avez affaire.

En outre, comme de nombreux utilisateurs ont signalé, il;. Est une situation un peu perverti où l'on passe un pointeur vers une fonction qui devrait le supprimer automatiquement si elle est allouée sur tas

Mais si vous insistez, néanmoins il y a des façons de découvrir quelle mémoire appartient à quel type.

vous avez fait avec 3 types de mémoire

  • Stack
  • Heap
  • Global

Par exemple:

char* p = new char[10]; // p is a pointer, points to heap-allocated memory

char* p = "Hello, world!"; // p is a pointer, points to the global memory

char p[] = "Hello, world!"; // p is a buffer allocated on the stack and initialized with the string

Maintenant, nous allons les distinguer. Je vais vous décrire cela en termes de Windows API et assembleur x86 (puisque c'est ce que je sais:))

Le début Let de la mémoire de la pile.

bool IsStackPtr(PVOID pPtr)
{
    // Get the stack pointer
    PBYTE pEsp;
    _asm {
        mov pEsp, esp
    };

    // Query the accessible stack region
    MEMORY_BASIC_INFORMATION mbi;
    VERIFY(VirtualQuery(pEsp, &mbi, sizeof(mbi)));

    // the accessible stack memory starts at mbi.BaseAddress and lasts for mbi.RegionSize
    return (pPtr >= mbi.BaseAddress) && (pPtr < PBYTE(mbi.BaseAddress) + mbi.RegionSize);
}

Si le pointeur est attribué sur la pile d'un autre fil que vous devriez obtenir son pointeur de pile par GetThreadContext au lieu de simplement prendre la valeur du registre de EIP.

mémoire globale

bool IsGlobalPtr(PVOID pPtr)
{
    MEMORY_BASIC_INFORMATION mbi;
    VERIFY(VirtualQuery(pPtr, &mbi, sizeof(mbi)));

    // Global memory allocated (mapped) at once for the whole executable
    return mbi.AllocationBase == GetModuleHandle(NULL);
}

Si vous écrivez une DLL vous devez mettre la poignée du module (qui est en fait son pointeur de la cartographie de base) au lieu de GetModuleHandle(NULL).

Heap

En théorie, vous pouvez supposer que si la mémoire est ni globale ni pile -. Il est attribué sur tas

Mais il y a est en fait une grande ambiguïté.

Vous devez savoir qu'il existe différentes implémentations du êtes des tas (comme tas brut de Windows accessible par HeapAlloc / HeapFree, ou malloc enveloppé CRT / ou free new / delete).

Vous pouvez supprimer un tel bloc par opérateur delete que si vous êtes sûr que ce soit était pile / pointeur global ou il a été par new alloué.

En conclusion:

  1. C'est un truc un peu pervers. Ne doit pas être utilisé en général. Il vaut mieux fournir des informations supplémentaires avec le pointeur qui indique comment la libérer.
  2. Vous ne pouvez l'utiliser si vous êtes sûr sur lequel tas la mémoire a été allouée (dans le cas où il est une mémoire de tas).

Je pense qu'il n'y a pas (facile) ainsi comment dire où la mémoire est allouée (vous pourriez être en mesure de déterminer à l'aide d'un débogueur, peut-être, mais ce n'est évidemment pas ce que vous voulez). La ligne de fond est:. Jamais faire la chose que vous avez fait dans le cas 2

Dans le cas 2, MyData = « valeur » provoque une fuite de mémoire car il n'y a plus une référence à la mémoire de retour de nouveau.

Il n'y a pas moyen facile ou moyen standard pour ce faire. Vous pouvez intercepter la fonction d'allocation de segment de mémoire (s) et de mettre chaque zone de mémoire allouée dans une liste. Votre fonction « IsHeap » doit vérifier si la zone est passé à la fonction est celle de la liste. Ceci est juste un soupçon -. Il est presque impossible de le faire d'une manière multi-plateforme

Mais là encore - pourquoi auriez-vous besoin que

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top