2010-07-26 65 views
5

在C++中,FF我有一个类,需要保持其可以被动态分配和用作指针,或不是会员,这样的:动态与非动态类成员

class A { 
    type a; 
}; 

class A { 
    A(); 
    ~A(); 
    type* a; 
}; 

,并在构造函数中:

A::A { 
    a = new type(); 
} 

和析构函数:

A::~A { 
    delete a; 
} 

除了需要更多代码的动态代码之外,其中还有其他优缺点吗?它们的行为是否有所不同(除了指针必须被解除引用)还是比另一个更慢?我应该使用哪一个?

+2

努力获得正确的可维护代码,然后在需要时处理性能问题。 – 2010-07-26 19:28:13

+1

你的第二个'A'是不安全的;你需要定义拷贝构造函数和'operator ='。永远不要拥有这样的指针,把它们包装起来,所以你不需要写任何*特殊的成员函数。 – GManNickG 2010-07-26 19:32:38

回答

0

随着指针你有更多的控制,但也更多的责任。您可以更精确地控制对象的生命周期,而没有指针时,生命期基本上等于包含对象的生命周期。而且,对于指针,成员实际上可以是指针类型的子类的实例。

性能方面,使用指针确实意味着更多的内存使用量,更多的内存碎片和取消引用确实花费大量时间。除了最具性能的关键代码之外,这些都不值得担心。

0

主要区别在于指针可能指向其他地方。

编辑

劳伦斯的回答是没有错,但它是一个有点普通。具体来说,动态分配会稍微慢一些。通过指针解引用同样会稍微慢一点。再次,这不是很多速度损失,它购买的灵活性可能是非常值得的。

0

主要区别在于,如果不使用指针,则内部成员的内存将被分配为分配给包含对象的内存的一部分。如果你使用的是new,你会在不同的块中获得内存(你似乎已经正确创建并破坏了所引用的对象)

0

当你使用原始指针时,你需要理解默认拷贝构造函数和拷贝赋值操作符的含义。原始指针在两种情况下都被复制。换句话说,你最终会有多个对象(或者原始指针)指向同一个内存位置。因此,如上所述的析构函数将尝试多次删除相同的内存。

5

有几个不同点:

  1. 每个成员的大小必须当你定义一个类是已知的。这意味着您必须包含您的头文件,并且您不能像使用指针成员一样使用前向声明(因为所有指针的大小都是已知的)。这对大型项目的混乱和编译时间有影响。

  2. 为数据成员的存储器是部分的包围类的实例,所以它会在同一时间被分配,在同一个地方,因为所有的其它类成员(是否在堆栈或堆上)。这对数据局部性有影响 - 将所有内容都放在同一个地方可能会导致更好的缓存利用率等。堆栈分配可能比堆分配快一点。声明太多庞大的对象实例可能会让你的堆栈更快。

  3. 指针类型管理起来比较棘手 - 因为它不会自动随类一起分配或销毁,所以您需要确保自己做到这一点。对于多指针成员来说,这变得非常棘手 - 如果你在构造函数中全部使用它们,并且在该过程中途出现异常,则析构函数不会被调用,并且你有内存泄漏。最好将指针变量分配给一个“智能指针”容器(如std::auto_ptr立即,这样就可以自动处理清理(并且不需要担心delete将它们放在析构函数中,通常可以避免写入一个)。而且,无论何时您手动处理资源,都需要担心复制构造函数和赋值运算符。

+0

添加智能指针容器 - 包括(stl/boost)到您的项目通常会比您自己的头文件增加更多的编译时间。被认为便宜的堆栈分配比堆分配快很多(这被认为是昂贵的)。 如果您要手动处理资源,为什么还需要考虑复制构造函数和赋值运算符?确保保持指向它们而不是复制它们。 (只需将副本/分配声明为私有,并且您永远不会犯错误)。 – Simon 2010-07-27 05:32:27

0

如果该成员变量应该住超越对象的生存期,或者它的所有权应转移到另一对象,则构件应该是动态(堆)使用“新”分配。如果不是,那么为了简化代码并减轻内存分配器的负担,将它作为类的直接成员通常是最好的选择。内存分配很昂贵。