当前位置: 首页 > 知识库问答 >
问题:

为什么我的对象似乎在堆上而没有使用“new”?

邓翼
2023-03-14

我开始学习动态内存分配的主题。

我有以下代码

#include <iostream>
#include "A.h"
#include "B.h"

using namespace std;

int main() {

   /* Both objects on Stack */

   A classAStack;
   B classBStack;

   /* Both objects on Heap*/
   //  A *classAHeap = new A();
   //  B *classBHeap = new B();

   /* A objects on Heap B ???*/
   A *classAHeap = new A();

   return 0;
}
#ifndef A_H_
#define A_H_

#include <iostream>
#include "B.h"

class A {
public:
   A();
   virtual ~A();

public:
   B b;
};

#endif /* A_H_ */
#include "A.h"

A::A() {
   std::cout <<"Constructor A called" << std::endl;
}

A::~A() {
}
#ifndef B_H_  
#define B_H_

#include <iostream>

class B {
public:
  B();
  virtual ~B();
};

#endif /* B_H_ */
#include "B.h"

B::B() {
  std::cout <<"Constructor B called" << std::endl;
}

B::~B() {
}

调试器的输出是:

Temporary breakpoint 6, main () at ../src/HeapStackTest02.cpp:18
18    A classAStack;

Breakpoint 4, B::B (this=0x23aa58) at ../src/B.cpp:12
12    std::cout <<"Constructor B called" << std::endl;

Breakpoint 5, A::A (this=0x23aa50) at ../src/A.cpp:13
13    std::cout <<"Constructor A called" << std::endl;

Breakpoint 4, B::B (this=0x23aa40) at ../src/B.cpp:12
12    std::cout <<"Constructor B called" << std::endl;

Breakpoint 4, B::B (this=0x60004b048) at ../src/B.cpp:12
12    std::cout <<"Constructor B called" << std::endl;

Breakpoint 5, A::A (this=0x60004b040) at ../src/A.cpp:13
13    std::cout <<"Constructor A called" << std::endl;

Breakpoint 1, main () at ../src/HeapStackTest02.cpp:30
30    return 0;

对于我的问题:

A的成员变量b在哪里?

如果我查看第0x23a节中的地址,它似乎是堆栈,而第0x6000节似乎是堆。

我正在使用Windows 64位系统。

为什么成员变量b也在堆上,而没有调用new运算符?

共有3个答案

潘佐
2023-03-14

考虑一下:

#include <iostream>
#include <string>

class B {
public:
    int64_t x = 42;
    int64_t y = 7;
};

class A1 {
public:
    B b;
};

class A2 {
public:
    A2() { b = new B(); }
    B* b;
    ~A2() { delete b; }
};

int main() {
    std::cout << sizeof(A1) << std::endl;   // prints 16
    std::cout << sizeof(A2) << std::endl;   // prints 8

    // Section (2)
    A1 a1;  // Instance of A1 and B are on the stack
    A2 a2;  // Instance of A2 is on the stack. B is on the heap.

    A1* a3 = new A1();
    std::cout << a3 == &(a3->b) << std:: endl;  // prints true

    A2* a4 = new A2();
    std::cout << a4 == a4->b << std::endl;  // prints false

    return 0;
}   
曹茂材
2023-03-14

为了回答这个问题,让我们从找出我们有多少B类型的实例开始。答案是3。

一个实例是类型A的成员b(在堆栈上)。另一个是堆栈上B的实例,第三个是堆上A类型的成员B的实例。

为什么会堆起来?它就在那里,因为您在堆上创建了类型A的实例,而A的实例的成员是B的实例。

所以B的三个实例中有一个在堆上,另外两个在堆栈上。

臧曜瑞
2023-03-14

成员是b是您动态分配的对象的一部分,因此它是该动态分配的一部分,并且位于内存中的同一位置。

如果成员不是对象的一部分,会剩下什么?你会动态分配什么?

这就是为什么在看到new时,应该避免使用术语“在堆上”。不仅仅是你的东西是“堆上的”。不,new动态分配一个对象以及该对象直接包含的所有内容。你如何写一个对象的声明和它是“在堆上”还是“在堆栈上”之间的任何心理联系都注定要失败。

确定物体存储时间的唯一可靠方法是了解其历史;确定对象存储位置的唯一可靠方法是不要麻烦,因为你不需要麻烦。

 类似资料:
  • 这应该是一个相对简单的问题,但它让我发疯。我正在尝试在JavaFX中创建扫雷器(主要用于练习),但我甚至无法显示一个简单的矩形。我以前运行过一次游戏,但我试图使游戏更加抽象,因此更容易编码,但我遇到了不显示任何问题。 我消除了所有无关的代码,使其尽可能简单。我基本上是在尝试创建一个名为Box的具有特定颜色和大小的矩形,将框添加到窗格中,并显示窗格。为了使Box成为可以在窗格上显示的节点,我使Box

  • 我需要一个数据结构用于我的用例。我应该能够将项目推入数据结构,并且我只想从堆栈中检索最后一个项目。JavaDoc for Stack表示:

  • 我是JProfiler的新手。我创建了一个非常简单的测试应用程序。这是一个带有main方法的Main.java: 注意,我暂停直到按键。通过这种方式,我确信主作用域在我按下一个键之前不会结束,所以我希望e存在并且不会被垃圾收集(如果这个假设不正确,请纠正我)。示例类: 我使用JProfiler Eclipse插件启动上述应用程序。我创建了一个基于完整仪器配置文件的会话;我已经删除了Java EE和

  • 我有一个Camel-ReST路由,它使用Jackson将集合转换为JSON,但当集合中的对象包含LocalDate时,它会抛出一个错误(没有LocalDate,一切都很好)。 com.fasterxml.jackson.databind.exc.:默认不支持Java8日期/时间类型:添加模块"com.fasterxml.jackson.datatype: jackson-datatype-jsr3

  • 日志输出为 日志输出为 为什么会这样?为什么不打印异常详细信息?我必须做什么才能获得堆栈跟踪信息? 日志框架:org.slf4j 1.7.26 logback 1.2.3

  • 问题内容: 我的用例需要一个数据结构。我应该能够将项目推送到数据结构中,而我只想从堆栈中检索最后一个项目。该堆栈的JavaDoc说: Deque接口及其实现提供了一组更完整和一致的LIFO堆栈操作,应优先使用此类。例如: 我绝对不希望这里出现同步行为,因为我将使用方法本地的数据结构。除了这个,我为什么还要在这里呢? PS:Deque的Javadoc说: 双端队列也可以用作LIFO(后进先出)堆栈。