首页 > 解决方案 > C++中的指针容器

问题描述

我正在阅读“使用 qt 在 c++ 中介绍设计模式”一书。在第 6 章中(参见书籍链接https://www.ics.com/designpatterns/book/containersofpointers.html),作者正在尝试编写一个继承自 QList 的库类。在addRefItem定义函数的示例 6.35 中。作者有非常奇怪的(至少对我来说)处理指针的方式。

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;
}

标签: c++qtpointerscontainers

解决方案


你觉得这很奇怪。你应该。如果可以避免的话,不要做这样的事情。一般来说,避免像瘟疫一样的手动内存管理。看看你是否可以用s替换它std::shared_ptr。这将需要一些工作,但结果会更加强大。

函数返回后它无论如何都会被破坏,对吧?

RefItem*& refitem提供对指针的引用,但是因为提供了引用,所以您知道传递给函数的任何对象都没有作用域,addRefItem因为它来自其他地方。如果它要被自动销毁,它将在其他地方被销毁。

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

您不知道对象refitem指向的对象是如何分配的,无论是自动分配还是动态分配,因此您不知道它何时会超出范围,但不会在addRefItem. refitem特别是 的使用delete refitem;表明它是动态分配的。如果不是,程序注定会出现Undefined Behavior

为什么ref's 的对象被破坏了?我们已经有一个了。为什么有两个?此代码将相同的 s 聚合RefItem为单个RefItem,维护该对象被复制的次数的计数,该计数存储在列表中。现在冗余的对象被销毁。这使得RefItem引用计数对象

代码块 1 显示,如果项目已经在列表中,则提供的对象将被销毁和释放,delete refitem;并且指向它的指针被清空,refitem = 0;以便更容易检测到该对象不再存在。如果此函数的调用者尝试使用空指针,则会发生未定义行为,但绝大多数系统,我在过去 20 年左右所做的一切工作,都会将使用检测为无效并崩溃程序。

这个我不太明白。与其将指针清空,不如将指针更新为指向列表中吸收并替换传入的指针的项。更完整的示例可以更好地解释这种选择。

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

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

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

附录:std::shared_ptr当此代码可以轻松实现时,为什么在此答案的序言中推荐 a std::unique_ptr?因为这段代码似乎正在实现一个引用计数指针。我可能是大错特错,在这种情况下std::unique_ptr是要走的路。只需unique_ptr从容器中删除它,让它退出范围,让系统为您处理破坏。如果这是一个用于从列表中检出和检入指向同一对象的指针的系统,std::shared_ptr那么它会为您完成所有这些工作,并且做得很好而且安全。为什么要std::unique_ptr在工作中使用工具包?


推荐阅读