我正在阅读《 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;
}

最佳答案

您会发现这很奇怪。你应该。如果可以避免,不要做这样的事情。通常,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来完成这项工作?

08-28 04:56