Как узнать, указывает ли указатель на кучу или стек?

Пример:

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 */ 

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

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

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

Нет никакого способа сделать это – и если вам нужно это сделать, что-то не так с вашим дизайном. Существует обсуждение того, почему вы не можете сделать это в более эффективном C ++ .

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

 stackBase = myTCB->stackBase; stackSize = myTCB->stackSize; if ((ptrStack < stackBase) && (ptrStack > (stackBase - stackSize))) isStackPointer1 = TRUE; 

Единственное «хорошее» решение, о котором я могу думать, это перегрузить operator new для этого classа и отслеживать его. Что-то вроде этого (скомпилированный код мозга):

 class T { public: void *operator new(size_t n) { void *p = ::operator new(n); heap_track().insert(p); return p; } void operator delete(void* p) { heap_track().erase(p); ::operator delete(p); } private: // a function to avoid static initialization order fiasco static std::set& heap_track() { static std::set s_; return s_; } public: static bool is_heap(void *p) { return heap_track().find(p) != heap_track().end(); } }; 

Тогда вы можете сделать так:

 T *x = new X; if(T::is_heap(x)) { delete x; } 

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

Итак, вытащите свою сборку ассемблера и сравните адрес указателя с указателем стека:

 int64_t x = 0; asm("movq %%rsp, %0;" : "=r" (x) ); if ( myPtr < x ) { ...in heap... } 

Теперь x будет содержать адрес, к которому вам придется сравнивать ваш указатель. Обратите внимание, что он не будет работать для памяти, выделенной в другом streamе, так как у нее будет свой собственный стек.

вот он, работает для MSVC:

 #define isheap(x, res) { \ void* vesp, *vebp; \ _asm {mov vesp, esp}; \ _asm {mov vebp, ebp}; \ res = !(x < vebp && x >= vesp); } int si; void func() { int i; bool b1; bool b2; isheap(&i, b1); isheap(&si, b2); return; } 

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

Во-первых, зачем вам это знать? Какую реальную проблему вы пытаетесь решить?

Единственный способ, которым я знаю, сделать такое определение, – это перегрузить глобальный operator new и operator delete . Затем вы можете задать менеджеру памяти, принадлежит ли ему указатель (куча) или нет (стек или глобальные данные).

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

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

В редких случаях для контейнера полезно отслеживать как принадлежащие им, так и не принадлежащие им указатели – либо с использованием флагов, либо путем их хранения отдельно. Однако большую часть времени проще просто установить четкую политику для любого объекта, который может содержать указатели. Например, большинство интеллектуальных указателей всегда имеют свои реальные указатели на контейнер.

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

В основных операционных системах стек растет сверху, а куча растет снизу. Таким образом, вы можете эвристически проверить, находится ли адрес за пределами большого значения, для некоторого определения «большой». Например, в моей 64-разрядной системе Linux работает следующее:

 #include  bool isHeapPtr(const void* ptr) { return reinterpret_cast(ptr) < 0xffffffffull; } int main() { int iStack = 35; int *ptrStack = &iStack; std::cout << isHeapPtr(ptrStack) << std::endl; std::cout << isHeapPtr(new int(5)) << std::endl; } 

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

Несмотря на громкие заявления об обратном, очевидно, что вы можете делать то, что хотите, в зависимости от платформы. Однако только потому, что что-то возможно, что автоматически не делает его хорошей идеей. Простое правило стека == no delete, иначе == delete вряд ли будет работать хорошо.

Более распространенный способ – сказать, что если я выделил буфер, тогда мне нужно его удалить. Если программа передает мне буфер, я не могу его удалить.

например

 class CSomething { public: CSomething() : m_pBuffer(new char[128]) , m_bDeleteBuffer(true) { } CSomething(const char *pBuffer) : m_pBuffer(pBuffer) , m_bDeleteBuffer(false) { } ~CSomething() { if (m_bDeleteBuffer) delete [] m_pBuffer; } private: const char *m_pBuffer; bool m_bDeleteBuffer; }; 

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

вот универсальный способ сделать это в 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; } 

Единственный способ, которым я получу это полу-надежно, – это то, что вы можете перегрузить 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 чтобы сделать что-то сложное, может помочь вам ответить на этот вопрос. Я все еще думаю, что если вы должны задать этот вопрос, вы сделали что-то очень неправильное.

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

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

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

 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(); } }; 

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

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

  • Динамическое распределение массива объектов
  • Можно ли программно определить размер массива C ++? А если нет, то почему?
  • Почему / когда использовать `intptr_t` для литья типов в C?
  • Удаляет ли вызов деструктор?
  • Безопасно ли удалять указатель на пустоту?
  • Объясните эту реализацию malloc из книги K & R
  • Как работает механизм сбора мусора?
  • Почему моя программа работает медленнее, если вы перебираете ровно 8192 элементов?
  • Методы classа, которые создают новые экземпляры
  • Ядро обнуляет память?
  • Динамический двумерный массив с указателем на указатель
  • Interesting Posts

    iphone error: expected ‘=’, ‘,’, ‘;’, ‘asm’ или ‘__attribute__’ перед ” foo ‘

    Передача списка объектов в MVC-controller с использованием jQuery Ajax

    Как использовать библиотеку поддержки Renderscript с Gradle

    Почтовая папка в C #

    Ошибка AndroidRuntime: Посылка: не удалось вывести значение маршала

    Где я должен найти драйверы для своего ноутбука, если он не поставляется с диском драйвера?

    Создание webfont с дополнительными многоязычными символами плоскости Unicode

    Программное обеспечение для управления ПК (рабочие станции)

    Что это означает, когда числовая константа в C / C ++ имеет префикс с 0?

    Autoincrement VersionCode с дополнительными свойствами gradle

    Копируемый ярлык / TextField / LabeledText в JavaFX

    Десериализация дат с форматом dd / mm / yyyy с использованием Json.Net

    Сборка скомпилированного исполняемого файла на Bash на Ubuntu в Windows не производит вывод

    Как я могу получить UIBarButtonItem с изображением и текстом?

    Предварительный просмотр текстовых файлов внутри Zip-файлов в Windows 10 File Explorer

    Давайте будем гением компьютера.