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

时间:2013-07-23 15:11:46

标签: c++

在C ++程序中,对于一个类,我们怎样才能获得静态创建并单独动态创建的任何时间点的活动对象数量?

5 个答案:

答案 0 :(得分:9)

可悲的是你不能。斯科特迈耶的其中一本书中有一个完整的部分,他继续讨论试图实现这一目标的挑战,但缺点是它是不可能的。

更有效的C ++ - 第27项:要求或禁止基于堆的对象。

好的,这是一个容易证明的问题(有问题的项目有几页,所以我不会总结所有内容,但这里至少有一个挑战):

许多(但不是全部)系统以下列方式安排记忆:

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

现在你可能会想到这样的记忆安排,你可以通过操作员new / new操作员做一些聪明的事情来弄清楚你是否在堆上或不正确(通过检查你是否高于或低于某个记忆地点)?这是问题所在。静态对象的位置取决于系统,因此可能发生以下情况:

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

您现在无法区分静态对象和堆对象。哎呀!另外你可能已经注意到我说这是系统相关的,这意味着即使你要想办法区分它们,你的代码也不会便携。

答案 1 :(得分:2)

警告:这使用了“未定义的行为”,如下所述 - 众所周知,它可以在MOST平台上运行(我已经足够理解它可以在Windows,Linux和Symbian OS上运行ARM和x86,并且应该可以使用大多数操作系统使用“平坦”内存模型)。

如果您将自己“限制”到特定系统,则可以将this与已知范围的“堆栈在哪里”(如果需要)静态数据进行比较。 [有可能找出堆栈对于任意线程的位置,但它使挑战更难一点]。

了解静态数据和堆栈的位置,我们可以进行比较

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++; 

请注意,这只有在您能够以某种方式确定堆栈的位置时才会起作用 - 当然,将this与其分配的块之外的任何内容进行比较是未定义的行为,因此从技术上讲,整体概念未定义。但是,在大多数OS /处理器体系结构中执行此操作是可能的。 [当然,你也需要做同样的事情,但在析构函数中反过来]。 (如果你从与创建它的线程不同的线程中销毁对象,它也会变得“有趣”!)

编辑:查找给定线程的堆栈并不难:在“第一个函数”中存储[每个线程,如果有多个线程]局部变量的地址(传入线程的那个创建调用)。然后在当前线程中获取变量的地址。这些值之间的任何内容都在该线程堆栈中,因为堆栈是一个连续的内存块。

答案 2 :(得分:0)

跟踪活动对象数量的最简单方法是创建一个对象管理器(使用GetSize()函数或其他)

在要跟踪的类中,还可以添加静态属性,该属性将分别在构造函数和析构函数中增加和减少。

使用对象管理器(动态分配)静态属性(所有分配)的大小,您将能够分别检索这些数字。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

您可以通过传递关于其位置的参数来告诉该类:

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

当然你可以欺骗这堂课。不。

此外,如果您希望减少干扰,可以将其作为模板并使用继承或封装,并在您的课程中使用它。只需给它一个参数:

template<class Tag>
LocationAware;

然后继承或保留类中的位置并初始化它。您可以使用LocationAware<YourClassOrTag>::xy_instances来查看实例。