创建指针列表的正确范例是什么?

时间:2019-01-16 17:20:33

标签: c++ memory-management

我经常发现自己 漫不经心地写了一些类,这些类添加了指向对象的指针,这些对象后来被销毁到列表中,这导致了很多段错误,但是问题是有时我只是可以't 提供了比存储指针列表更好的解决方案。在我看来,似乎没有一种简单的方法可以在C ++中“存储无法复制的临时对象”。我缺少有效地执行此操作的范例吗?

例如,我将有一个看起来像这样的类:

class MyClass
public:
   std::vector<OtherClass *> other_objects;
   void method() {
      OtherObject other_object = create_other_object();
      other_objects.push_back(&other_object);
   }

您可能要执行此操作的原因之一是因为您在其他地方使用了other_objects(作为其他函数的参数),并且您无法复制OtherObject实例(如果{{1 }}例如,复制构造函数是私有的。

当然,一旦您尝试在代码中的其他地方使用OtherObject,每个指针指向的内存将被销毁。

我编写了很多Python代码,并且经常使用这种结构非常,其中一种方法使用仅存在于该方法范围内的对象填充可迭代对象。有没有办法在C ++中有效地做到这一点?我可以做自己的内存管理来使方法中的临时对象保持活动状态,超出方法范围吗?

2 个答案:

答案 0 :(得分:6)

  

在C ++中创建指针列表的正确范例是什么?

结合std::listcontainer之类的smart pointer类(请参见herestd::shared_ptr(或其他std::unique_ptr)。

根据经验(有时是错误的),请避免使用raw pointers并喜欢使用智能指针。 Memory management是一个棘手的话题。如果您阅读有关garbage collection的书(例如GC handbook),您将学习相关的概念,术语和技术(即使在manual memory management中也适用,例如reference counting,有人认为这是GC的原始形式)。 Circular references很难处理(请注意weak references,例如std::weak_ptr)。

在这里需要很多时间和时间来详细解释所有这些内容(我没有时间或动力,甚至没有全部技能)。阅读一本不错的C++ programming书,并参考一些C++ reference(后来可能会参考C++11标准n3337或更新的东西)。请注意,(对于任何人)都很难理解C ++的memory model

请注意rule of five

在某些操作系统和/或C ++实现中,您可以找到工具,例如valgrindaddress sanitizerClangGCC调试,然后避免使用memory leaks(详细信息取决于编译器和/或OS)。在少数情况下(可能是少数),您可以考虑使用垃圾收集器库(例如Boehm's GC,请参阅thisMPS )。

  

有没有办法在C ++中有效地做到这一点?

我不知道任何有效,通用和简单的方法(并且Rice's theorem让我相信不可能有一种方法)来管理内存。您的里程会有所不同。您需要精确地了解内存管理以及其他编程约束和目标,并做出自己的权衡。请参阅Norvig的opinion。有No Silver Bullet


PS。 C ++是一种极其困难的编程语言。准备好花费很多时间(几年而不是几个月;也许几十年)并努力学习它。为了获得启发,还请看一些用C ++编写的写得好的free software的源代码。我并没有声称自己是C ++的高手(即使我的日常工作是为它设计和实现一些静态源代码analyzers)。我相信在这个星球上可能只有几十个(或几百个)C ++大师,而我不在其中。

PPS。我有偏见,但我建议在您的开发机器上使用using Linux来学习C ++编程,正是因为它具有许多有用的工具。

答案 1 :(得分:5)

不,您没有理由这样做:

  OtherObject other_object = create_other_object();
  other_objects.push_back(&other_object);

这将创建一个临时对象,然后将指针存储在列表中,然后销毁该对象。

这是Python的主要区别。在Python中,每个对象都是对Python对象的引用,甚至是整数。在C ++中,您在堆栈上(如您的对象)或在堆上(通过newmake_unique ...创建)有对象。如果要模仿Python的行为,则需要在堆上放置对象。

只有三种有效的模式,具体取决于create_object()的作用:

  • 它创建一个对象并按值返回它。在这种情况下,请用make_unique包装它以获得副本。这种模式通常不是很有用,也不实用。
  • 它在堆上创建一个新对象,并期望调用代码来处理内存管理。因此,原型为:std::unique_ptr<OtherClass> create_other_object();
  • 它会创建一个新对象,但不希望调用代码来处理内存管理,在这种情况下,原型应为OtherClass* create_other_object();

在您的情况下,可能是第二种情况:

std::vector<std::unique_ptr<OtherClass>> other_objects;
void method() {
    other_objects.push_back(create_other_object());
}