简体   繁体   中英

static and dynamic memory allocation of objects in C++

在C ++程序中,对于一个类,我们如何获得静态创建和动态创建的任何时间点的活动对象数量?

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.

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.

The easiest solution to track the number of active objects is to create an object manager (with a GetSize() function or whatever)

In the class you want to trace, you can also add a static property which will be increased and decreased in constructors and destructors respectively.

With the size of the object manager (dynamic allocation) and the static property (all allocations) you will be able to retrieve those numbers separately.

作为一个选项,你可以全局重载new和delete来增加/减少一些静态计数器,这将给出动态分配对象的全局计数......

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM