堆栈上的 C++ 实例变量存储为指针
Posted
技术标签:
【中文标题】堆栈上的 C++ 实例变量存储为指针【英文标题】:C++ instance variable on stack stored as a pointer 【发布时间】:2015-06-05 14:02:27 【问题描述】:我在堆栈上创建了一组简单的 Dummy 对象:
Dummy a(8);
Dummy b(9);
Dummy dummies[2] = a,b;
有一个 MyObject 对象。我在堆栈上创建了它。构造函数将这个数组存储到一个实例变量中。
class MyObject
Dummy* _dummies;
MyObject obj(Dummy* dummies):
: _dummies(dummies)
;
MyObject obj(dummies);
当obj被移除并调用其析构函数时,_dummies的内存是否被释放?我知道堆栈上的实例变量是自动释放的,但是 MyObject 怎么知道这个指针指向堆栈上的数组,而不是指向在堆上创建的 Dummy 对象?
在构造函数中,虚拟数组是按值传递还是按引用传递?它是一个指针,但它毕竟是堆栈上的一个数组。
我了解堆栈、堆、按值和引用传递,但堆栈上的数组用指针处理真的让我很困惑。我一直用vector,因为它清晰简单,但我也想了解简单的数组。
编辑:谢谢大家。现在我明白 MyObject 与数组的生命周期没有任何关系。当虚拟数组超出范围时,它会被删除。
但是:如果将“Dummy”替换为“char”会怎样?在堆栈上有一个 char* (例如从函数返回)并将其传递给一个对象,然后通过将指针保存到第一个 char 来存储它是非常标准的。那也是一种不好的做法吗? (我将使用 std::vector 和 std::string 代替,更简单...)
【问题讨论】:
你有“新”的东西吗?如果没有,不用担心。 除非你通过“new”创建内存,否则无需担心释放它。当它超出范围时,它将从堆栈中弹出。 这样的数组根本没有传递给构造函数。构造函数接收指向数组第一个元素的指针。 【参考方案1】:您需要注意,您的实例变量 _dummies 只是一个指针。创建对象时,传递给构造函数的指针会存储到 _dummies 中,仅此而已。该指针可以是 NULL、堆栈上的数组地址、malloc 返回的指针或许多其他东西。你的对象不知道。
如果数组消失而对象仍然存在,那么如果在此之后使用该对象就会有麻烦。您有责任确保数组仍然存在,直到最后一次访问对象中的 _dummies。并且您负责在对象消失后以某种方式删除数组本身。所以你的构造有点危险,除非你小心使用它会崩溃。
【讨论】:
【参考方案2】:您唯一需要担心的是,您是否在 Dummy
类中使用了 new
。如果您没有,则无需担心。当堆栈上的对象超出范围时,它们会被自动删除。
【讨论】:
【参考方案3】:当obj被移除并调用其析构函数时,_dummies的内存是否被释放?
不,但这不是问题,如果我正确理解了您的示例,因为“_dummies 的内存”在堆栈上,当它超出范围时将被释放(独立于被销毁的 MyObject 实例)。
我知道堆栈上的实例变量是自动释放的,但是 MyObject 怎么知道这个指针指向堆栈上的一个数组,而不是指向在堆上创建的 Dummy 对象?
它没有。正如我上面所说,MyObject 析构函数不会自动释放 _dummies 指向的任何已分配内存。
在构造函数中,虚拟数组是按值传递还是按引用传递?它是一个指针,但它毕竟是堆栈上的一个数组。
它是堆栈上的数组,而不是指针。在表达式中使用时,它“衰减”为指针(指向数组中的第一个元素)。因此,它是通过引用传递的(但不是作为 C++ 引用!)。
【讨论】:
【参考方案4】:您的Dummy* _dummies;
成员变量可能指向也可能不指向某个实际内存位置。管理此位置是您的责任,而不是默认构造函数。因此,如果您使用类外部的指针对其进行初始化,则当实例被销毁时,指向的内存不会发生任何事情,只是指针会消失。如果你在你的类中创建(新)一个实例,你必须在析构函数中释放(删除)它。
从实际的角度来看,您可能需要考虑智能指针,例如 C++11 中的 std::shared_ptr 以使这些任务更不容易出错。
【讨论】:
【参考方案5】:当obj被移除并调用其析构函数时,_dummies的内存是否被释放?
不,不是。如果你想释放与任何指针相关的内存,你必须明确地这样做,例如如果_dummies
是动态数组,则输入delete[] _dummies
。
MyObject 怎么知道这个指针指向栈上的一个数组而不是堆上创建的 Dummy 对象?
它没有。这意味着如果您在堆栈分配的Dummy dummies[2] = a,b;
超出范围并被删除后尝试访问MyObject
中的_dummies
,您可能会遇到段错误。
在构造函数中,虚拟数组是按值传递还是按引用传递?
其类型Dummy[]
被强制转换为指针类型Dummy*
,然后按值传递。
【讨论】:
你不应该不delete[] _dummies
如果它指向的数组是在堆栈上分配的,就像在OPs问题中一样。以上是关于堆栈上的 C++ 实例变量存储为指针的主要内容,如果未能解决你的问题,请参考以下文章
C++ 父类指针如何调用子类的变量和函数 虚函数virtual实例