Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static and dynamic memory allocation of objects in C++

Tags:

c++

In a C++ program, for a class, how can we get the counts of the number of active objects at any point of time which are statically created and dynamically created separately??

like image 351
user2611177 Avatar asked Jul 23 '13 15:07

user2611177


3 Answers

Sadly you just can't. There's a whole section in one of the books by Scott Meyer's where he goes on about the challenges of trying to achieve this and the short of it is it's not possible.

More Effective C++ - Item #27: Requiring or prohibiting heap-based objects.

Ok here's one of the problems that is easily demonstrated (the item in question is several pages long so I won't summarize all of it but here's at least one challenge):

Many (but not all) systems arrange their memory in the following fashion:

----------------
|     Stack    |
| (Grows Down) |
|              |
----------------
|              |
|              |
|              |
|              |
|              |
|              |
----------------
|     Heap     |
|  (Grows Up)  |
|              |
----------------

Now you might think with a memory arrangement like this you could do something clever with operator new/new operator to figure out if you're on the heap or not right (by checking if you're above or below a certain memory location)? Here's the problem. Where static objects go is system dependent, so the following thing could happen:

----------------
|     Stack    |
| (Grows Down) |
|              |
----------------
|              |
|              |
|              |
|              |
|              |
|              |
----------------
|     Heap     |
|  (Grows Up)  |
|              |
----------------
|    Static    | 
|    Objects   |
----------------

You now fail to distinguish between static objects and heap object. Oops! Also you may have noticed I said this is system dependent, which means even if you were to figure out a way to distinguish between them, well your code would not be portable.

like image 130
Borgleader Avatar answered Nov 16 '22 00:11

Borgleader


Caveat: This uses "unedfined behaviour", as described below - it is known to work on MOST platforms (I have enough understanding to say this works on ARM and x86 in Windows, Linux and Symbian OS's, and should be fine for most OS's that use a "flat" memory model).

If you "limit" yourself to a particular system, it could be possible to compare this to a known range of "where the stack is" (and if need be) where static data is). [It would be possible to figure out where the stack is for an arbitrary thread too, but it makes the challenge a little harder].

With the knowledge of where static data, and stack is located, we can compare

char *this_addr = static_cast<char*>(this);
if (this_addr >= globa_start && this_addr <= global_end) 
   globals++;
else if (this_addr >= stacK_top && this_addr >= stack_base)
   stacked++;
else heaped++; 

Note that this will only work if you can actually somehow figure out where the stack is - and of course, it's undefined behaviour to compare this with anything outside the block it was allocated in, so technically, the whole concept is undefined. However, it's POSSIBLE to do this in most OS/Processor architectures. [Of course, you also need to do the same but in reverse in the destructor]. (It also gets "fun" if you destroy the object from a different thread than the one that created it!)

Edit: Finding the stack for a given thread isn't that hard: Store [per thread if there are more than one thread] the address of a local variable in the "first function" (the one passed into the thread create call). Then take the address of a variable in the current thread. Anything between those values is in that threads stack, as the stack is one contiguous lump of memory.

like image 45
Mats Petersson Avatar answered Nov 15 '22 22:11

Mats Petersson


You could simply tell the class by passing an argument about its location:

class LocationAware {
public:
    enum Location { STATIC, STACK, HEAP };
    explicit LocationAware(Location location) : my_location(location) {
        switch(location) {
            case STATIC: ++static_instaces; break;
            case STACK: ++stack_instances; break;
            case HEAP: ++heap_instances; break;
        }
    }

    ~LocationAware() {
        switch(my_location) {
            case STATIC: --static_instaces; break;
            case STACK: --stack_instances; break;
            case HEAP: --heap_instances; break;
        }
    }

private:
    const Location my_location;

public:
    static unsigned static_instaces;
    static unsigned heap_instances;
    static unsigned stack_instances;
};

unsigned LocationAware::static_instaces = 0;
unsigned LocationAware::heap_instances = 0;
unsigned LocationAware::stack_instances = 0;

LocationAware stat(LocationAware::STATIC);

int main() {
    LocationAware stack(LocationAware::STACK);

    LocationAware * heap = new LocationAware(LocationAware::HEAP);
}

Of course you can lie to this class. Don't.

Also, if you would like to make it less intrusive you could make it a template and use inheritance or encapsulation and use it from your class. Just give it a parameter:

template<class Tag>
LocationAware;

Then either inherit or hold a location in your class and initialize it. You can see the instances using LocationAware<YourClassOrTag>::xy_instances.

like image 26
Fozi Avatar answered Nov 15 '22 22:11

Fozi