Как узнать, указывает ли указатель на кучу или стек? - PullRequest
27 голосов
/ 12 июля 2010

Пример:

bool isHeapPtr(void* ptr)
{
     //...
}

int iStack = 35;
int *ptrStack = &iStack;
bool isHeapPointer1 = isHeapPtr(ptrStack); // Should be false
bool isHeapPointer2 = isHeapPtr(new int(5)); // Should be true
/* I know... it is a memory leak */

Почему, я хочу знать это:

Если у меня в классе указатель на член, и я не знаю, является ли указывающий объект новым. Тогда я должен использовать такую ​​утилиту, чтобы узнать, нужно ли мне delete указатель.

Но:
Мой дизайн еще не сделан. Итак, я запрограммирую это так, как я всегда должен delete. Я собираюсь избегать мусорного программирования

Ответы [ 14 ]

1 голос
/ 12 июля 2010

вот универсальный способ сделать это в Windows, используя TIP:

bool isStack(void* x)
{
    void* btn, *top;
    _asm {
        mov eax, FS:[0x08] 
        mov btn, eax
        mov eax, FS:[0x04] 
        mov top, eax
    }
    return x < top && x > btn;
}

void func()
{

    int i;

    bool b1;
    bool b2;

    b1 = isStack(&i);
    b2 = isStack(&si);

    return;
}
0 голосов
/ 12 июля 2010

Ваш дизайн не должен полагаться на определение этой информации (как уже отмечали другие, это на самом деле невозможно). Вместо этого ваш класс должен явно определять владение указателями, которые он принимает в своем конструкторе или методах. Если ваш класс становится владельцем этих указателей, то неправильно указывать указатель на стек или глобал, и вы должны удалить его, зная, что некорректный клиентский код может привести к сбою. Если ваш класс не вступает во владение, он не должен удалять указатель.

0 голосов
/ 12 июля 2010

Как вы могли не знать, выделено ли что-то в куче или нет?Вы должны спроектировать программное обеспечение так, чтобы оно имело единственную точку выделения.

Если вы не делаете какие-то действительно экзотические вещи во встроенном устройстве или работаете глубоко в пользовательском ядре, я просто не вижу необходимости.

Посмотрите на этот код (без проверки, для примера):

class A
{
int *mysweetptr;

A()
{
   mysweetptr = 0; //always 0 when unalloc'd
}

void doit()
{
   if( ! mysweetptr)
   {
       mysweetptr = new int; //now has non-null value
   }
}

void undoit()
{
   if(mysweetptr)
   {
      delete mysweetptr;
      mysweetptr = 0;  //notice that we reset it to 0.
   }
}

bool doihaveit()
{
   if(mysweetptr)
     return true;
   else 
     return false; 
}
~A()
{
   undoit();
}
};

В частности, обратите внимание, что я использую нулевое значение, чтобы определить, был ли указательвыделено или нет, или если мне нужно удалить его или нет.

0 голосов
/ 12 июля 2010

Единственный способ, с помощью которого я знаю, это делать с полубезопасностью, если вы можете перегрузить operator new для типа, для которого вам нужно это сделать. К сожалению, здесь есть несколько серьезных подводных камней, и я не могу вспомнить, что они из себя представляют.

Я знаю, что одна ловушка состоит в том, что что-то может быть в куче без непосредственного распределения. Например:

class A {
   int data;
};

class B {
 public:
   A *giveMeAnA() { return &anA; }
   int data;
   A anA;
};

void foo()
{
   B *b = new B;
   A *a = b->giveMeAnA();
}

В приведенном выше коде a в foo заканчивается указателем на объект в куче, который не был выделен с помощью new. Если ваш вопрос действительно «Как я могу узнать, могу ли я позвонить delete по этому указателю». перегрузка operator new, чтобы сделать что-то хитрое, может помочь вам ответить на этот вопрос. Я все еще думаю, что если вам нужно задать этот вопрос, вы сделали что-то очень неправильное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...