C++ 中的指针容器

container of pointers in c++

本文关键字:指针 C++      更新时间:2023-10-16

我正在阅读"使用 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;
}

你觉得这很奇怪。你应该。如果可以避免,不要做这样的事情。通常,请避免像瘟疫一样手动进行内存管理。看看是否可以将其替换为std::shared_ptrs。这将需要一些工作,但结果会更加强大。

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

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

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

你不知道refitem点的对象是如何分配的,它是自动分配的还是动态分配的,所以你不知道它什么时候会超出范围,但它不会在addRefItem中自动销毁。refitem的使用,特别是delete refitem;,表明它是动态分配的。如果不是,该程序注定要进行未定义的行为。

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

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

这个我不太明白。我不会将指针清空,而是更新指针以指向列表中吸收并替换传入的指针的项目。一个更完整的例子可以更好地解释这种选择。

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

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

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

附录:当此代码可以使用std::unique_ptr轻松实现时,为什么要建议在此答案的序言中std::shared_ptr?因为此代码似乎正在实现引用计数指针。我可能大错特错,在这种情况下std::unique_ptr就是要走的路。只需从容器中取出unique_ptr,让它超出范围,让系统为您处理销毁。如果这是一个用于从列表中检出和插入指向同一对象的指针的系统,std::shared_ptr会为您完成所有这些操作,并且做得又好又安全。为什么要让std::unique_ptr做这项工作?

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

这意味着,如果您只是将其作为指针传递,您仍然可以执行refitem = 0;但是当函数返回时,该值不会结转。因此,作为指针引用传递可以实现这一点。

我不明白最后两行是做什么的。为什么需要删除"refitem"。

refItem是一个指针(根据设计指向分配的内存),必须在某处删除。查看代码,作者正在分配此函数删除它的责任。

关键问题是作者希望确保当函数返回addRefItem(),如果成功删除refitem的值应设置为 null。如果指针没有与引用一起传递,这是不可能的。