【问题标题】:Questions about Memory Management, Stack, and Heap [duplicate]关于内存管理、堆栈和堆的问题 [重复]
【发布时间】:2011-11-28 01:24:01
【问题描述】:

可能重复:
Does this type of memory get allocated on the heap or the stack?

我有一些与记忆有关的问题,希望你们能够回答。考虑这段代码,Foo 代表一个包含大量方法和大量原始数据成员的大类:

class Foo {
  public:
    Foo() : // Initialize all data members ...
        { }

    // Lots of methods ...

    ~Foo() { /*Nothing needed here ... correct?*/ }

private:
    int    a;
    int    b;
    char   c;
    double d;
    // Lots of other primitive data members (no pointers) ...
};

class Bar {
  public:
    void func() {
        foo = new Foo();
    }

    // Assuming Bar::func() is always called before deletion ...
    ~Bar() { delete foo; }
  private:

    Foo* foo;
};

int main() {
    Bar bar;
    bar.func();

    Bar* barptr;
    barptr->func();

    return 0;
}

我的问题是,当我调用bar.func() 时,Foo 的所有数据成员是否都分配在 stack 内存或 heap 内存上(我知道foo 会在堆上......我想!)?当我打电话给barptr->func() 时呢?例如,Foo::a 是在堆栈上还是在堆上?

此外,我是否需要明确删除Foo::~Foo() 中的任何内容? Foo只有原始的本地数据成员,没有一个函数使用newmalloc()

如果我完全不知道我在说什么,如果有人能解释这些数据的存储位置,我将不胜感激。

【问题讨论】:

  • @sehe:我怀疑这是微软文本表示的产物。
  • 另外:en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization 描述了为什么当 C++ 正确完成时析构函数通常是空的。
  • @sehe:你确定吗?我的Linux浏览器的复制粘贴操作没有出现这种现象,但在Windows上偶尔会出现。不知道为什么它没有每次都发生 - 也许有一些内部黑客来修复它。
  • @wallyk:我希望 SO 提议去聊天,我不知道该怎么做。我 90% 的时间在 Linux 上使用 Opera。它肯定会使用 CRLF 将所有 SO 文本复制到剪贴板 - 我需要在 vim 中一直使用:%s/^M//g
  • 多余的空格只是一种编码风格。它不是任何东西的神器。

标签: c++ memory memory-management


【解决方案1】:

new 分配的所有东西都在堆上,包括它的所有成员。 foo = new Foo(); 行在堆上创建了一个 Foo(包括 所有 个成员)。
只有命名对象在堆栈上。在您的情况下,barBar)和barptr(指向Bar 的指针)。 Foos 析构函数不需要做任何事情,这实际上很常见,如果您正确使用 RAII,就像 C++ 方式一样。

在您的main 函数中,bar 是堆栈上的一个区域,它是一个Bar,它在堆上分配一个Foo。如果barptr; 实际被初始化,barptr 将是堆栈上的一个区域,它是指向某处的Bar 的指针(也许堆栈可能不是)。但是,在每种情况下,Bars foo 成员都会在堆上分配,因为这是 Bars 构造函数告诉它要做的事情。

在您的main 函数中,bar 是堆栈上的一个区域,它是一个(指向(大型基元集合)的指针),它在堆上分配一个(大型基元集合)。
如果barptr; 被实际初始化,barptr 将是堆栈上的一个区域,它是指向某处(可能不是堆栈)的(指向(大型原语集合)的指针)的指针。但是,在每种情况下,(大量原语)都将分配在堆上,因为这是构造函数告诉它要做的事情。

因为我知道有人会提到它,所以堆/堆栈的区别是编译器的突发奇想,并没有以任何方式标准化。完全允许“作弊”并将东西放在其他地方,如果喜欢的话。例如,全局对象通常既不在堆栈也不在堆上,而是在另一个地方。此外,尽管频繁(明显)使用内存管理,这就是 C# 和 java 发展如此之快的原因。编译器经常“作弊”并将“动态范围”的对象放入堆栈。

【讨论】:

  • 感谢您非常详细的回复!非常感谢!
【解决方案2】:

当您调用 new Foo() 时,您正在堆上创建一个新的 Foo 对象。

Foo 中的所有原始数据成员都存储在 Foo 对象中。因此,它们也在堆上——在 Foo 对象内部。

您的 Foo 析构函数不需要显式处理原始数据成员。它也不需要显式地处理类类型的成员;它们的析构函数将在 Foo 的析构函数之后自动调用。

具有指向动态分配的对象的裸指针的类通常需要在析构函数中显式声明来处理该对象。你可以通过使用像std::auto_ptrboost::shared_ptr.这样的智能指针来避免这种情况

【讨论】:

    猜你喜欢
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 2017-04-28
    • 2020-10-10
    • 2012-09-23
    • 2011-08-15
    • 1970-01-01
    相关资源
    最近更新 更多