C++类成员:堆栈与堆分配
C++ Class Member: Stack vs. Heap Allocation
考虑一个像这样的类
class Element{
public:
// approx. size of ~ 2000 Byte
BigStruct aLargeMember;
// some method, which does not depend on aLargeMember
void someMethod();
}
现在假设 Element 的许多实例(例如,运行时有 100,000,000 个实例,同时存在大约 50,000 个实例(是在运行时创建的,并且通常只调用someMethod()
,而无需为aLargeMember
分配内存。 (这个说明性示例派生自非线性有限元代码,类Element
实际上表示有限元。
现在我的问题:由于aLargeMember
不是经常需要的,并且考虑到大量的Element
实例,动态创建aLargeMember
是否有利?例如
class Element{
public:
// approx. size of ~ 2000 Byte
std::unique_ptr<BigStruct> aLargeMember;
// only called when aLargeMember is needed
void initializeALargeMember{
aLargeMember = std::unique_ptr<BigStruct>( new BigStruct() );}
// some method, which does not depend on aLargeMember
void someMethod();
}
基本上,这对应于 https://stackoverflow.com/a/36646563/4859499 中给出的建议4:
仅在有明确需求时才使用 new,例如:
一个特别大的分配,会占用大部分堆栈(您的操作系统/进程将"协商"一个限制,通常在 1-8+ 兆字节范围内(
- 如果这是使用动态分配的唯一原因,并且确实希望对象的生存期与函数中的范围相关联, 您应该使用本地 std::unique_ptr<> 来管理动态 内存,并确保无论您如何离开范围,它都已释放: 通过返回,投掷,打破等。(您也可以使用 std::unique_ptr<> 类/结构中的数据成员,用于管理对象拥有的任何内存。
所以,我的问题是:本案中的堆方法是否被认为是不好的做法?或者在本案中是否有任何反对堆的好论据?提前谢谢你!
C++类成员:堆栈与堆分配
不要将基于堆栈的分配与具有堆分配对象的成员变量混淆。如果您有此类的堆分配对象:
class Element{
public:
// approx. size of ~ 2000 Byte
BigStruct aLargeMember;
// some method, which does not depend on aLargeMember
void someMethod();
}
然后,堆栈上不会分配此处的任何内容。
由于 aLargeMember 不是经常需要的,并且考虑到 元素的大量实例,是否有利于 动态创建大型成员?
您描述的场景确实是动态内存分配的合法候选者,因为不这样做只会使您分配比您需要的更多,而没有收益 - 因此您没有太多其他选择。
本案中的堆方法是否被视为不良做法?
这个问题有点太笼统了,很容易被解释为基于意见,但在给定代码段的上下文中,您似乎指的是根据需要使用分配成员变量的场景,因此进行延迟初始化可能更可取,以减轻必须手动维护代码中每个点的初始化的开销。为此,您可以包装对此成员的访问,以确保返回已初始化的内容。只是为了说明,非常不线程安全,这个想法是这样的:
class Element{
private:
// approx. size of ~ 2000 Byte
std::unique_ptr<BigStruct> aLargeMember;
// A wrapper through which you access aLargeMember
BigStruct& GetLargeMember()
{
if (!aLargeMember)
{
aLargeMember = std::make_unique<BigStruct>();
}
return *aLargeMember;
}
public:
// some method, which might depend on aLargeMember
void someMethod();
};
如果您需要传递它以在类范围之外使用,那么您将面临悬而未决的引用的危险,因为拥有unique_ptr
的已分配实例可能已经被销毁。如果是这种情况,并且您真的想保证不要这样做,那么unique_ptr
不合适,因为您只能移动它。相反,请考虑使用shared_ptr
并从GetLargeMember()
返回实际的智能指针。
或者在本案中是否有任何反对堆的好论据?
不反对在这里使用堆,但至少有几种模式可用于处置。例如,鉴于您打算创建如此大量的实例,但同时存在的实例要少得多,我会认真考虑池化class Element
的实例。
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 从堆栈分配的原始指针构造智能指针
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 巨大的内存分配:堆栈与堆
- 有效地分配堆栈对象(由函数的值返回)到堆?
- 为什么不能在 Visual C++ 中动态分配堆栈内存?但海湾合作委员会可以做到
- 为什么分配堆内存比分配堆栈记忆更快
- 安全分配堆栈分配的阵列
- 附加到具有非动态分配堆栈的向量
- 是否随作用域分配和解除分配堆栈帧
- 在执行中脱离堆栈对象的范围之前,请分配堆栈对象
- 全局阵列分配 -- 堆栈或堆
- 如何使新操作员超载以分配堆栈
- 具有类作用域的动态分配堆栈内存
- 如何在 Linux 下为可执行文件分配堆栈
- 内存分配堆栈
- 成员函数内存分配堆栈或堆
- 在 c++ 中重新分配堆栈上的对象
- 防止为类和派生类分配堆栈
- 如何防止msvc++为switch语句过度分配堆栈空间?