c ++

时间:2019-06-17 01:58:27

标签: c++ qt pointers containers

我正在阅读《 qt c ++设计模式简介》这本书。在第6章(请参见书籍链接https://www.ics.com/designpatterns/book/containersofpointers.html)中,作者试图编写一个从QList继承的库类。在示例6.35中,定义了addRefItem函数。作者有非常奇怪的方式(至少对我而言)处理指针。

void Library::addRefItem(RefItem*& refitem) { 

在这里,作者使用了指针引用*&,他解释说“以便删除后可以进行空赋值”。我认为这与最后两行有关。

   QString isbn(refitem->getISBN());
   RefItem* oldItem(findRefItem(isbn));
   if(oldItem==0)
      append(refitem);
   else {
      qDebug() << isbn << " Already in list:\n"
               << oldItem->toString()
               << "\nIncreasing number of copies " 
               << "and deleting new pointer." ;
      int newNum(oldItem->getNumberOfCopies() + refitem->getNumberOfCopies());
      oldItem->setNumberOfCopies(newNum);
      delete refitem;                         
      refitem = 0;                            
   }
}

我不明白最后两行的含义。为什么refitem需要删除。函数返回后无论如何都会破坏它,对吗?然后为什么需要将refitem分配为0。

removeRefItem函数中,也有类似的行delete ref,请参见下文。谁能帮我理解所有这些?非常感谢。

int Library::removeRefItem(QString isbn) {
   RefItem* ref(findRefItem(isbn));
   int numCopies(-1);
   if(ref) {
      numCopies = ref->getNumberOfCopies() - 1;
      if(numCopies== 0) {
         removeAll(ref);
         delete ref;
      }
      else
         ref->setNumberOfCopies(numCopies);
   }
   return numCopies;
}

2 个答案:

答案 0 :(得分:3)

您发现这很奇怪。你应该。如果可以避免,不要做这样的事情。通常,Avoid manual memory management喜欢瘟疫。查看是否可以replace this with std::shared_ptrs。这将需要一些工作,但结果将更加可靠。

  

函数返回后它会被破坏,对吗?

不。 RefItem*& refitem提供了对指针的引用,但是由于提供了引用,因此您知道传递给函数的任何对象都不在addRefItem范围内,因为它来自其他地方。如果要自动销毁它,它将在其他地方销毁。

  

我不明白最后两行的含义。为什么需要删除“ refitem”。函数返回后无论如何都会破坏它,对吗?然后为什么需要将“ refitem”指定为0。

您不知道对象refitem所指向的对象是如何分配的,无论它是automatically or dynamically allocated,所以您不知道它何时会超出范围,但不会自动已在addRefItem中销毁。 refitem(特别是delete refitem;)的使用表明它是动态分配的。如果不是,该程序注定要Undefined Behaviour

为什么ref的对象被破坏?我们已经有一个。为什么要两个?这段代码将相同的RefItem聚合为一个RefItem,维护了该对象被复制的次数(存储在列表中)。现在冗余的对象被销毁。这使RefItem成为reference-counted object

代码块1显示,如果该项目已在列表中,则使用delete refitem;破坏并释放所提供的对象,并使用refitem = 0;将指向该对象的指针为空,以便更容易地检测到该对象不再存在。如果此函数的调用者尝试使用空指针,则会发生“未定义行为”,但是在过去20多年左右的时间里,绝大多数系统(我所做的所有工作)都会检测到该用法无效并崩溃。程序。

我不太了解。我不会更新指针,而是将其更新为指向列表中吸收和替换传入的指针的项目。更完整的示例可能会更好地解释此选择。

顺便说一句,不要使用0来使指针为空。与0(C ++ 11或更高版本)或nullptr(C ++ 11之前的版本)相比,用NULL识别代码的难度更大。 0有很多含义。 nullptr有一个。

  

在removeRefItem函数中,也有类似的行“ delete ref”,请参见下文。谁能帮我理解所有这些?非常感谢。

在第二个代码示例中,如果未完成副本的数量(引用计数)减少为0,则removeRefItem销毁并释放ref

附录:为什么可以很容易地用std::shared_ptr实现此代码,为什么在此答案的序言中推荐std::unique_ptr?因为此代码似乎正在实现引用计数的指针。我可能会犯错,在这种情况下,std::unique_ptr是必经之路。只需从容器中删除unique_ptr并将其移出范围,让系统为您处理破坏。如果这是一个用于从列表中检出并检入指向同一对象的指针的系统,则std::shared_ptr将为您完成所有这些工作,并且安全,好地完成。为什么要{std::unique_ptr来完成这项工作?

答案 1 :(得分:0)

  

作者使用了指针引用*&,他解释说“以便删除后可以进行空赋值”。我认为这与最后两行有关。

这意味着,如果仅将其作为指针传递,则仍然可以执行refitem = 0;,但该函数返回时该值将不会保留。因此,将其作为指针引用来实现。

  

我不明白最后两行的含义。为什么需要删除“ refitem”。

refItem是一个指针(按设计指向分配的内存),必须将其删除。通过查看代码,作者将删除此功能的职责分配给了该功能。

关键问题在于作者希望确定addRefItem()函数何时返回,如果成功删除refitem的值,则应将其设置为null。如果没有通过引用传递指针,这将是不可能的。