简体   繁体   中英

container of pointers in c++

I am reading the book "an introduction to design patterns in c++ with qt". In chapter 6, (see the book link https://www.ics.com/designpatterns/book/containersofpointers.html ), the author is trying to write a library class which is inherited from QList. In the example 6.35 where the addRefItem function is defined. The author has very weird (at least for me) way to deal with the pointers.

void Library::addRefItem(RefItem*& refitem) { 

here, the author used a pointer reference *&, he explained "so that null assignment after delete is possible". this is related to the last two lines, I assume.

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

I don't understand what the last two lines do. Why refitem need to be deleted. It will be destructed anyway after the function return, right? and then why refitem need to be assigned to be 0.

In the removeRefItem function, there is also a similar line, delete ref , see below. Can anyone help me understand all of these? A lot of thanks.

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

You find this weird. You should. Don't do stuff like this if you can avoid it. In general, Avoid manual memory management like the plague. See if you can replace this with std::shared_ptr s . It will take a bit of work, but the result will be much more robust.

It will be destructed anyway after the function return, right?

No. RefItem*& refitem provides a reference to a pointer, but because a reference is provided, you know that any object passed into the function is not scoped within addRefItem because it came from elsewhere. If it is to be automatically destroyed it will be destroyed in this elsewhere.

I don't understand what the last two lines do. Why "refitem" need to be deleted. It will be destructed anyway after the function return, right? and then why "refitem" need to be assigned to be 0.

You don't know how the object refitem points at was allocated, whether it is automatically or dynamically allocated so you don't know when it will go out of scope, but it won't be automatically destroyed in addRefItem . The usage of refitem , specifically delete refitem; , suggests that it was dynamically allocated. If it wasn't the program is doomed to Undefined Behaviour .

Why is ref 's object destroyed? We already have one. Why have two? This code aggregates RefItem s that are the same into a single RefItem , maintains a count of the number of times this object has been duplicated, that is stored in the list. The now-redundant object is destroyed. This makes RefItem a reference-counted object .

Code block 1 shows that if the item is already in the list, the provided object is destroyed and freed with delete refitem; and the pointer to it is nulled with refitem = 0; so that it's easier to detect that the object is no more. Should the caller of this function try to use the nulled pointer, Undefined Behaviour will occur, but the vast majority of systems, everything I've worked on over the past 20 years-or-so, will detect the usage as invalid and crash the program.

This I don't quite understand. Rather than nulling the pointer, I would have updated the pointer to point at the item in the list that absorbed and replaced the pointer passed in. A more complete example may explain this choice better.

As an aside, don't use 0 to null a pointer. It's harder to discern what the code is up to with a 0 when compared to a nullptr (C++11 or newer) or a NULL (pre C++11). 0 has many meanings. nullptr has one.

In the removeRefItem function, there is also a similar line, "delete ref", see below. Can anyone help me understand all of these? A lot of thanks.

In the second code sample, removeRefItem destroys and frees ref if the number of outstanding copies, the reference count, is reduced to 0.

Addendum: Why recommend a std::shared_ptr in the preamble to this answer when this code could easily be implemented with std::unique_ptr ? Because this code appears to be implementing a reference-counted pointer. I could be dead wrong and in that case std::unique_ptr is the way to go. Simply remove the unique_ptr from the container and let it drop out of scope to let the system handle destruction for you. If this is a system for checking out and in pointers to the same object from a list, std::shared_ptr does all that for you, and does it well and safely. Why kit-bash a std::unique_ptr into doing the job?

The author used a pointer reference *&, he explained "so that null assignment after delete is possible". this is related to the last two lines, I assume.

What this means is if you just pass it as a pointer, you can still do refitem = 0; but that value will not be carried over when the function returns. So passing as pointer reference achieve that.

I don't understand what the last two lines do. Why "refitem" need to be deleted.

The refItem is a pointer (to an allocated memory by design) and it has to be deleted somewhere. Looking at the code, the author is assigning this function the responsibility to delete it.

The key issue is that the author want to make sure when addRefItem() function returns, the value of refitem should be set to null if it was successfully deleted. This wouldn't have been possible if it the pointer was not passed with reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM