将对象成员显式放在堆上(通过new)是否被视为不礼貌/不良做法?我认为您可能希望允许客户端选择内存区域来实例化对象.我知道可能存在堆成员可能被接受的情况.如果你知道某种情况可以描述一下吗?
如果你有一个专为复制语义而设计的类,并且你不必要地分配/释放一堆内存,我可以看到这是不好的做法.但总的来说,事实并非如此.有很多类可以使用堆存储.只要确保你没有内存泄漏(在析构函数中释放内容,引用计数等),你就可以了.
如果您想要更多灵活性,请考虑让您的用户指定分配器.我会解释一下.
某些类(例如std::vector
字符串,映射等)需要它们所代表的数据结构的堆存储.它不被认为是不礼貌的; 当你自动分配时vector
,用户应该知道vector
在调用构造函数时分配了一个缓冲区:
void foo() { // user of vector knows a buffer that can hold at least 10 ints // gets allocated here. std::vectorfoo(10); }
同样地,因为std::string
,你知道有一个内部堆分配char*
.每个string
实例是否有一个通常取决于STL实现; 通常他们被引用计数.
但是,对于几乎所有的STL类,用户都可以选择放置的位置,因为它们可以指定分配器. vector
是这样定义的:
template> class vector { // etc. };
在内部,vector
使用Alloc
(默认为默认分配器用于T的任何内容)来分配缓冲区和它可能需要的其他堆存储.如果用户不喜欢默认分配策略,他们可以指定自己的一个:
vectorfoo(10);
现在,当构造函数分配时,它将使用MyCustomAllocator
而不是默认值.以下是编写自己的STL分配器的一些细节.
如果您担心在类中使用堆来存储特定存储可能是"不礼貌",您可能需要考虑为您的类的用户提供这样的选项,以便他们可以指定如何分配事物.您的默认策略不符合他们的需求.
我根本不认为这是不好的做法.您可能希望通过new显式分配成员变量的原因有很多种.这里有几个我的头顶.
假设你的类有一个非常大的缓冲区,例如512kb或1MB.如果此缓冲区未存储在堆上,则如果用户创建了类的多个局部变量,则可能会超出默认堆栈空间.在这种情况下,在构造函数中分配缓冲区并将其存储为指针是有意义的.
如果您正在进行任何类型的引用计数,则需要一个指针来跟踪实际指向数据的对象数量.
如果您的成员变量的生命周期与您的类不同,那么指针就是您的选择.一个完美的例子是懒惰评估,如果用户要求,您只需为成员的创建付费.
虽然它不一定对您的用户有直接的好处,但编译时间是使用指针而不是对象的另一个原因.如果在类中放置一个对象,则必须在头文件中包含定义该对象的头文件.如果使用指针,则可以转发声明类,并且只包含在需要它的源文件中定义类的头文件.在大型项目中,使用前向声明可以通过减少编译单元的总体大小来大大加快编译时间.
另一方面,如果您的用户创建了很多类的实例以供在堆栈上使用,那么使用对象代替成员变量的指针将是有利的,因为堆分配/解除分配比较慢.考虑到上面的第一个子弹,在这种情况下避免堆更有效.