考虑像这样的类
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,例如:
一个特别大的分配,它将占用大量堆栈(您的OS /进程将“协商”一个限制,通常在1-8 MB以上的范围内)
- 如果这是您使用动态分配的唯一原因,并且您确实希望将对象的生存期绑定到函数中的作用域, 您应该使用本地std :: unique_ptr <>来管理动态 内存,并确保无论您如何离开示波器都将其释放: 通过返回,抛出,中断等。(您也可以使用std :: unique_ptr <> 类/结构中的数据成员,以管理对象拥有的任何内存。)
因此,我的问题是:在当前情况下,堆方法是否被视为不良做法?还是在当前情况下对堆有任何好的论点?预先谢谢你!
答案 0 :(得分:3)
C ++类成员:堆栈与堆分配
不要将基于堆栈的分配与为堆分配对象的成员变量混淆。如果您有此类的堆分配对象:
class Element{
public:
// approx. size of ~ 2000 Byte
BigStruct aLargeMember;
// some method, which does not depend on aLargeMember
void someMethod();
}
然后在这里没有任何内容分配到堆栈。
由于不经常需要aLargeMember,因此请考虑 大量的Element实例,对 动态创建aLargeMember?
您所描述的场景确实是动态内存分配的合理候选者,因为如果不这样做,只会使您分配的方式超出您的需求,没有好处-因此您没有太多其他选择。
在当前情况下,堆方法是否被视为不良做法?
这个问题有点太笼统了,很容易解释为基于观点,但是在给定的代码段中,您似乎指的是根据需要分配成员变量的场景-basis,因此最好使用la lazy initialization,以便减轻必须手动维护代码中要求的每个点的初始化的开销。为此,您可以包装对此成员的访问权限以确保您返回已初始化的内容。仅出于说明目的,不是很线程安全,它的思路大致如下:
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()
返回实际的智能指针。
或者在当前情况下是否有针对堆的良好论证?
此处不反对使用堆,但是至少可以使用几种模式进行处理。例如,假设您打算创建大量实例,但同时创建的实例少得多,那么我将认真考虑pooling class Element
的实例。