为啥我的对象似乎在堆上而不使用`new`?

Posted

技术标签:

【中文标题】为啥我的对象似乎在堆上而不使用`new`?【英文标题】:Why does my object appear to be on the heap without using `new`?为什么我的对象似乎在堆上而不使用`new`? 【发布时间】:2017-09-10 19:38:19 【问题描述】:

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

我有以下代码:

#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() 

调试器的输出是:

临时断点6,main()在../src/HeapStackTest02.cpp:18 18 A类AStack; 断点 4,B::B (this=0x23aa58) at ../src/B.cpp:12 12 std::cout

我的问题:

A 类的成员变量 b 在哪里?

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

我正在使用 Windows 64 位系统。

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

【问题讨论】:

因为任何A 都包含B。这是一个真正的组合。 【参考方案1】:

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

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

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

确定对象存储持续时间的唯一可靠方法是了解其历史;确定对象存储位置的唯一可靠方法是不要打扰,因为您不需要。

【讨论】:

【参考方案2】:

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

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

为什么它在堆上? 它在那里,因为您在堆上创建了类型 A 的实例,并且 A 的实例具有 B 的实例作为成员。

所以 B 的 3 个实例之一在堆上,另外 2 个在堆栈上。

【讨论】:

【参考方案3】:

考虑一下:

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

【讨论】:

以上是关于为啥我的对象似乎在堆上而不使用`new`?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 char[] 在堆栈上,而 char * 在堆上?

Java中对象都是分配在堆上吗?你错了!

使用类模板时在堆上创建对象

C++如何只在堆上或者栈上生成对象

在 Java 中不使用“new”关键字声明数组

new和new[]的区别