我正在阅读《 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_ptr
s。这将需要一些工作,但结果将更加可靠。
函数返回后无论如何都会破坏它,对吗?
否。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
来完成这项工作?