home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 31,928 of 33,346   
   Ulrich Eckhardt to All   
   Re: Politics of using the standard libra   
   14 Feb 12 17:16:59   
   
   91494cfd   
   From: ulrich.eckhardt@dominolaser.com   
      
   Am 13.02.2012 19:34, schrieb P. Areias:   
   > Let's see a (easier) list: a replacement for std::list but with C++11   
   > syntax. I can explain it in detail and why it is better than std::list   
   > (take a peek at the destructor and then look at the STL   
   > implementations).   
      
   I can explain why most standard library implementations (I avoid the term STL,   
   because it's technically incorrect) are better than your template class.   
      
      
   > template   
   > struct List;   
   > template   
   > struct ListIndex;   
   >   
   > template   
   > struct ListNode   
   > {...};   
   >   
   > template   
   > struct ListIndex   
   > {...};   
      
   First question: Which of these is for public use?   
      
      
   >     ListIndex(ListNode* plistnode):_listnode(plistnode)   
   >     {}   
   >     ListIndex(const ListIndex&   
   > listindex):_listnode(listindex._listnode)   
   >     {}   
      
   I'd suggest using "explicit" on one-argument ctors.   
      
      
   >     ListIndex&  operator++()   
   >     {   
   >         _listnode=_listnode->_next;   
   >         return *this;   
   >     }   
   >     ListIndex&  operator--()   
   >     {   
   >         _listnode=_listnode->_previous;   
   >         return *this;   
   >     }   
      
   Missing assert(_listnode). Missing diagnostic mode overall.   
      
      
   >     ListIndex&  operator=(const ListIndex&  listindex)   
   >     {   
   >         if(this!=&listindex)   
   >         {   
   >             _listnode=listindex._listnode;   
   >         }   
   >         return *this;   
   >     }   
      
   Useless comparison, self-assignment isn't harmful here. The check and branch   
   is typically harder on the CPU's pipeline than the avoided assignment.   
      
      
   > template   
   > struct List   
      
   Missing allocator support.   
      
      
   >     Index start() const   
   >     {   
   >         Index temp;   
   >         temp._listnode=_start;   
   >         return temp;   
   >     }   
      
   Should use initialization instead of abusing its friendship to assign to the   
   pointer afterwards. Dito for finish().   
      
      
   >     bool valid(const Index&  index) const   
   >     {   
   >         return index._listnode;   
   >     }   
      
   The fact that this is attached to the class makes it less flexible than the   
   iterator approach of the STL. The point is that in order to pass a range to a   
   function, you must pass beginning, end and the container, whereas with an   
   iterator you only have to    
   pass the beginning and the end. This makes it also possible to construct a   
   sequence that is not based on a container.   
      
      
      
   >     List(const List& otherlist):   
   >         _start(0),_finish(0),_numberofelements(0)   
   >     {   
   >         each(it,otherlist)   
   >         {   
   >             insertafter(finish(),otherlist(it));   
   >         }   
   >     }   
      
   Not exception-safe. If inserting inside the ctor throws, you wont get the   
   destructor called since the object hasn't been constructed yet.   
      
      
   >     virtual ~List()   
   >     {   
   >         destroy();   
   >     }   
      
   This virtual is useless, it only causes overhead. If you think you need to   
   derive from a class that doesn't provide any virtual functions for   
   customization, you are usually wrong. In all other cases, you want private   
   inheritance.   
      
      
   >     ValueType&  operator()(const Index&  index)   
      
   Unusual. I'd prefer operator[] for consistency with built-in arrays.   
   Otherwise, having a separation between position and access is indeed something   
   missing in the standard library containers.   
      
      
   >     List&  operator=(const List&  other)   
   >     {   
   >         if(this!=&other)   
   >         {   
   >             destroy();   
   >             each(it,other)   
   >             {   
   >                 insertafter(finish(),other(it));   
   >             }   
   >         }   
   >         return *this;   
   >     }   
      
   Not exception-safe, if copying throws, you have already thrown away your   
   former content. Use copy and swap instead.   
      
      
   >     friend ostream&  operator<<(ostream&  os,const List& quantity)   
   >     friend istream&  operator>>(istream&  is,List&  quantity)   
      
   This couples the container to one specific textual output format usable only   
   in combination with std::iostreams. If the element type is std::string, you   
   will get ambiguous outputs easily. If the element type is std::wstring, you   
   don't get any output but    
   compiler errors.   
      
   >     friend void writing(fstream&  os,const List&  quantity)   
   >     friend void reading(fstream&  is,List&  quantity)   
      
   Same as for textual IO, only that binary dumps are even less usable for   
   serialization. Generic containers give you the means to access and store   
   elements and the ability to extend this with the serialization you want.   
      
      
   Further:   
   - Missing swap().   
   - Missing subrange constructor.   
   - Missing complexity guarantees/documentation.   
   - No access to the size.   
   - Number of elements is stored in an int, this should be size_t for   
   portability (e.g. to 64-bit platforms!).   
   - "Easier than std::list" is marketing-speak, if you want to say something,   
   provide facts please!   
   - No support for sorting.   
      
   I'm sorry if I have to disappoint you, but your container class is far away   
   from industry-proven C++ standard library implementations. In particular, your   
   testsuite should be enhanced to verify the behaviour in out-of-memory   
   conditions. I'd also question    
   if your testsuite is comparable in range to those of usual C++ i   
   plementations, and this is also something that matters!   
      
      
   That said, you _can_ outperform and outfeature the containers of the standard   
   library sometimes. However, this first requires proof that it's necessary and   
   then it requires lots of work, planning, measuring and testing, a task that   
   usually isn't worth    
   the hassle, and it typically isn't as generic either.   
      
   Uli   
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca