Can a C++ class determine whether it's on the stack or heap?

后端 未结 15 2136
有刺的猬
有刺的猬 2020-12-13 04:14

I have

class Foo {
....
}

Is there a way for Foo to be able to separate out:

function blah() {
  Foo foo; // on the stack
         


        
相关标签:
15条回答
  • 2020-12-13 04:28

    Overload new() for your class. This way you'll be able to tell between heap and stack allocation, but not between stack and static/global.

    0 讨论(0)
  • 2020-12-13 04:29

    As mentioned above, you need to control how your object is allocated through overloaded new operator. Watch out for two things however, first the 'placement new' operator that initializes your object inside the memory buffer preallocated by user; second, nothing stops the user from simply casting arbitrary memory buffer into your object type:

    char buf[0xff]; (Foo*)buf;
    

    Another way is the fact that most runtimes use a bit more memory than asked when doing heap allocations. They usually place some service structure there to identify proper deallocations by pointer. You could inspect your runtime implementation for these patterns, although it will make your code really unportable, dangerous and unsupportable overkill.

    Again, as mentioned above, you really are asking for solution details ("how") when you should ask about the initial problem you devised this solution for ("why").

    0 讨论(0)
  • 2020-12-13 04:30

    The meta question as asked by pax is asked "why would you want to do that" you'll likely get a more informative answer.

    Now assuming you're doing this for "a good reason" (perhaps just curiousity) can get this behaviour by overriding operators new and delete, but don't forget to override all 12 variants including:

    new, delete, new no throw, delete no throw, new array, delete array, new array no throw, delete array no throw, placement new, placement delete, placement new array, placement delete array.

    One thing you can do is put this in a base class and derive from it.

    This is kind of a pain, so what different behavior did you want?

    0 讨论(0)
  • 2020-12-13 04:30

    There is a solution, but it forces inheritance. See Meyers, "More Effective C++", Item 27.

    EDIT:
    Meyers' suggestion is summarized in an article written by Ron van der Wal, which Meyers himself linked to in his blog (in this post):

    Tracking heap based objects

    As an alternative to the global variable approach, Meyers presents a HeapTracked class that uses a list to keep track of the addresses of class instances allocated off the heap, then uses this information to determine if a particular object resides on the heap. The implementation goes like this:

    class HeapTracked {
      // Class-global list of allocated addresses
      typedef const void *RawAddress;
      static list<RawAddress> addresses;
    public:
      // Nested exception class
      class MissingAddress {};
    
      // Virtual destructor to allow dynamic_cast<>; pure to make
      // class HeapTracked abstract.
      virtual ~HeapTracked()=0;
    
      // Overloaded operator new and delete
      static void *operator new(size_t sz)
      {
        void *ptr=::operator new(sz);
        addresses.push_front(ptr);
        return ptr;
      }
    
      static void operator delete(void *ptr)
      {
        // Remove ‘ptr’ from ‘addresses’
        list<RawAddress>::iterator it=find(addresses.begin(),
    
        addresses.end(), ptr);
        if (it !=addresses.end()) {
          addresses.erase(it);
          ::operator delete(ptr);
        } else
          throw MissingAddress();
      }
    
      // Heap check for specific object
      bool isOnHeap() const
      {
        // Use dynamic cast to get start of object block
        RawAddress ptr=dynamic_cast<RawAddress>(this);
        // See if it’s in ‘addresses’
        return find(addresses.begin(), addresses.end(), ptr) !=
          addresses.end();
      }
    };
    
    // Meyers omitted first HeapTracked:: qualifier...
    list<HeapTracked::RawAddress> HeapTracked::addresses; 
    

    There is more to read on the original article: Ron van der Wal comments on this suggestion, and then demonstrates other alternative heap tracking methods.

    0 讨论(0)
  • 2020-12-13 04:36

    A more direct, and less intrusive method would be to look up the pointer in the memory region maps (such as /proc/<pid>/maps). Each thread has a region allocated to its stack. Static and global variables will live in the .bss section, constants in a rodata or const segment, and so on.

    0 讨论(0)
  • 2020-12-13 04:37

    A way for MFC classes:

    .H

    class CTestNEW : public CObject
    {
    public:
        bool m_bHasToBeDeleted;
        __declspec(thread) static void* m_lastAllocated;
    public:
    #ifdef _DEBUG
        static void* operator new(size_t size, LPCSTR file, int line) { return internalNew(size, file, line); }
        static void operator delete(void* pData, LPCSTR file, int line) { internalDelete(pData, file, line); }
    #else
        static void* operator new(size_t size) { return internalNew(size); }
        static void operator delete(void* pData) { internalDelete(pData); }
    #endif
    public:
        CTestNEW();
    public:
    #ifdef _DEBUG
        static void* internalNew(size_t size, LPCSTR file, int line)
        {
            CTestNEW* ret = (CTestNEW*)::operator new(size, file, line);
            m_lastAllocated = ret;
            return ret;
        }
    
        static void internalDelete(void* pData, LPCSTR file, int line)
        {
            ::operator delete(pData, file, line);
        }
    #else
        static void* internalNew(size_t size)
        {
            CTestNEW* ret = (CTestNEW*)::operator new(size);
            return ret;
        }
    
        static void internalDelete(void* pData)
        {
            ::operator delete(pData);
        }
    #endif
    };
    

    .CPP

    #include "stdafx.h"
    .
    .
    .
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    void* CTestNEW::m_lastAllocated = NULL;
    CTestNEW::CTestNEW()
    {
        m_bHasToBeDeleted = (this == m_lastAllocated);
        m_lastAllocated = NULL;
    }
    
    0 讨论(0)
提交回复
热议问题