简体   繁体   English

C ++中对象的静态和动态内存分配

[英]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. 更有效的C ++ - 第27项:要求或禁止基于堆的对象。

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)? 现在你可能会想到这样的内存安排,你可以通过operator new / new运算符做一些聪明的事情来判断你是在堆上还是不正确(通过检查你是在某个内存位置之上还是之下)? 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). 警告:这使用了“未定义的行为”,如下所述 - 众所周知,它可以在MOST平台上运行(我已经足够理解它可以在Windows,Linux和Symbian OS中运行ARM和x86,对于大多数操作系统来说应该没问题。使用“平坦”记忆模型)。

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). 如果“限制”自己特定的系统,它可能是能够比较this以“堆栈的”已知范围内(如果需要的话),其中静态数据)。 [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. 请注意,这只有在您能够以某种方式确定堆栈的位置时才会起作用 - 当然,将this与分配的块之外的任何内容进行比较是未定义的行为,因此从技术上讲,整个概念是未定义的。 However, it's POSSIBLE to do this in most OS/Processor architectures. 但是,在大多数OS /处理器体系结构中执行此操作是可能的。 [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) 跟踪活动对象数量的最简单方法是创建一个对象管理器(使用GetSize()函数或其他)

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 . 您可以使用LocationAware<YourClassOrTag>::xy_instances查看实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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