对于由其他对象组成的C ++类,使这些成员对象成为指针是一种好习惯吗?

时间:2014-06-30 20:30:35

标签: c++ memory-management

我要问的是关于会员" mylist"的更好的做法:

像这样声明mylist:

class MyClaz {
  std::list<string> mylist;
  ...
}

或者声明这样:

class MyClaz {
  std::list<string> *mylst;
  MyClaz();
  ...
}

MyClaz::MyClaz() {
  myList = new std::list<string>();
}
// plus destructor to delete myList

在第一种情况下,当创建MyClaz实例时,是否会自动分配mylist?当MyClaz被销毁时,它会被正确清理吗?

有没有理由使用第二种情况?这似乎更危险。

6 个答案:

答案 0 :(得分:10)

仅在需要时谨慎使用指针。没有指针有许多优点,包括不必手动管理对象的生命周期和数据局部性。问题应该是是否有任何理由使用第二个案例......

答案 1 :(得分:2)

要回答您的第一个问题,是的,mylist将自动分配并自动销毁,这就是为什么第二种方法一般都不好。

请注意,自动创建的mylist将是一个空字符串。

答案 2 :(得分:2)

  

将这些成员对象作为指针是好的做法吗?

通常没有 1 。使用C ++标准库容器,尤其没有

sizeof(std::list<string>)非常小,课程管理着自己的一生。每个列表元素都将被列表析构函数销毁,这将由您自动创建的析构函数自动调用。

使用new创建容器完全没有意义。

  

在第一种情况下,当创建MyClaz实例时,是否会自动分配mylist?当MyClaz被销毁时,它会被正确清理吗?

是的,是的。

mylist的构造函数调用MyClaz的默认构造函数,mylist的析构函数调用MyClaz的析构函数(如果你不这样做)写一个 - 编译器为你创建一个)

1 - 有一些原因你应该使用指针(例如PIMPL,多态),但在这些情况下你使用智能指针std::shared_ptr,{ {1}}),而非原始指针std::unique_ptr)。

答案 3 :(得分:1)

在容器中没有任何意义,因为那时你必须担心在析构函数中删除它。最好的方法是使用method1。也许你可能想要一个std :: list的引用而不是实际的对象。

此外,如果您使用STL,最好使用智能指针(例如std :: shared_ptr),这样您就不必担心在其上调用delete。

std::shared_ptr<std::list<string>> mylist;
//in constructor
mylist = std::make_shared<std::list<string>>();
//in destructor it will be deleted automatically

//if you want to have a list of references rather than objects themselves
std::list<std::shared_ptr<string>> mylist;
希望它有所帮助。

答案 4 :(得分:1)

在大多数情况下,使用对象而不是指针是有意义的。但是,有一些例外,使用指针是有意义的。了解例外情况很好。

我发现最令人信服的原因是,当列表预计在大多数时间为空时,将列表作为成员变量是很昂贵的。构建一个可以避免大多数对象的列表的内存和时间成本。

以下是CAD / CAE应用程序中经常出现的简化示例。

class Attribute;

class Entity
{
   std::list<Attribute*>* attributes;
};

class Attribute: public Entity
{
};

大多数Entity都没有Attribute,但会有很多人Entity。就Part而言,这些是使用指定的数据。 Entity可能来自Color,可能具有Density等视觉属性,Face等材质属性。但是,Part的{​​{1}}可能有自己的Color。如果没有自己的Color,则Face会继承其Part Color

使用std::list<Attribute*>*代替std::list<Attribute*>的关键原因是,当大多数对象不需要时,为每个对象创建一个列表可能会很昂贵。指针将分配给构造函数中的NULL。当一个对象需要在列表中有一个项目时,将从堆中分配一个列表并在此后使用。

额外的逻辑伴随着额外的维护负担,但成本可以证明收益是合理的。

<强>更新

由于各种原因,我们仍然需要在Windows 7(64位)上使用Microsoft Visual Studio 2008。在那个平台上,

sizeof(std::list<Attribute*>)是48

sizeof(std::vector<Attribute*>)是40

sizeof(std::vector<Attribute*>*)是8。

使用g ++ 4.7.3(32位),大小为:

sizeof(std::list<Attribute*>)是8

sizeof(std::vector<Attribute*>)是12

sizeof(std::vector<Attribute*>*)是4。

根据您的平台,对象与指针的额外成本可能过高。必须根据平台上的数字进行判断。

答案 5 :(得分:1)

当您考虑指针时,请考虑生命周期费用。如果你有一个指针,那么当你想要使用它时,无论指针指向指针可能存在哪些 ,你的代码将处理这两种情况 。虽然这可以提供很大的灵活性并且可以提高性能,但这需要付出代价。

  • 您不能再假设存在指向的内容,并且需要代码来处理这两种情况 - 何时存在以及何时不存在。
  • 您现在必须非常小心如何使用STL - 例如:将对指针进行比较而不是指向它们。
  • 您的代码现在容易受到整类指针相关错误的攻击。<​​/ li>

C ++是一种可以让你做任何事情的语言。 假设您知道自己在做什么

所以问题的答案是,只有当你知道为什么需要它们时才使用指针。

如果,在你的脑海中,你正在思考,“也许指针可能更好”,那么答案是否定的,他们不是。为什么?因为你不清楚使用指针的成本,从长远来看,这对你的代码来说弊大于利。请记住,C ++再次假设您知道自己在做什么。

另一方面,如果您决定不使用指针,那么您应该使用什么?完全按照您的方式使用它:

class MyClaz {
  std::list<std::string> mylist; //I assume you meant std::string here
  ...
}

目前,信任编译器。不要担心按值复制。担心你的代码和你做它想做的事情有多好和多么清楚。这是一个很好的做法。

所以一般来说,良好的做法是只在你有充分理由这样做时才做出改变。