Re: Politics of using the standard library
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<typename ValueType>
struct List;
template<typename ValueType>
struct ListIndex;
template<typename ValueType>
struct ListNode
{...};
template<typename ValueType>
struct ListIndex
{...};
First question: Which of these is for public use?
ListIndex(ListNode<ValueType>* 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<typename ValueType>
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<ValueType>& 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<ValueType>& 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<ValueType>& quantity)
friend istream& operator>>(istream& is,List<ValueType>& 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<ValueType>& quantity)
friend void reading(fstream& is,List<ValueType>& 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++ implementations, 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! ]