我正在阅读《 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;
}
答案 0 :(得分:3)
您发现这很奇怪。你应该。如果可以避免,不要做这样的事情。通常,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
来完成这项工作?
答案 1 :(得分:0)
作者使用了指针引用*&,他解释说“以便删除后可以进行空赋值”。我认为这与最后两行有关。
这意味着,如果仅将其作为指针传递,则仍然可以执行refitem = 0;
,但该函数返回时该值将不会保留。因此,将其作为指针引用来实现。
我不明白最后两行的含义。为什么需要删除“ refitem”。
refItem
是一个指针(按设计指向分配的内存),必须将其删除。通过查看代码,作者将删除此功能的职责分配给了该功能。
关键问题在于作者希望确定addRefItem()
函数何时返回,如果成功删除refitem
的值,则应将其设置为null。如果没有通过引用传递指针,这将是不可能的。