Re: Politics of using the standard library
Syntax-wise, C++03 and C++11 are large but not scarily so.
Syntax-wise, C++03 and C++11 allow a finer grain of control than more
recent languages and this is an obvious advantage.
The Standard Libraries are, in my perspective, scary to approach,
learn and use. Iterators in various forms, inserters, indices, etc.
Sort Algorithms which directly sort the values, confusing "help"
functions that are just silly (for_each??)
Even std::vector is horrible to use sometimes. What about pre-defined
IO, what about a true sort member function, etc?
Note that Algorithms are procedural functions and therefore even
experienced programmers tend to forget that they are there.
I don't see any advantage in using the Standard Libraries (either 03
and 11) compared to a roll-your-own library, besides the time spent in
writing or adapting code.
Frankly, arguments such as the one of initialization show prejudice
"we did this and it was painful, therefore you shouldn't have the
capacity to do it...".
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).
/*
* QC 0-> Compiles, Works in a verification test and was compiled with
* g++ -std=c++0x -Wall -Wextra -Wunused-variable -Winit-self -Wunused
-Werror -Wparentheses -pedantic -Weffc++
*/
#pragma once
#include "../utils/utils.hpp"
namespace containers
{
/**
* @cond
*/
template<typename ValueType>
struct List;
template<typename ValueType>
struct ListIndex;
template<typename ValueType>
struct ListNode
{
public:
friend struct List<ValueType>;
friend struct ListIndex<ValueType>;
private:
ListNode<ValueType>* _previous;
ListNode<ValueType>* _next;
ValueType _value;
public:
ListNode(const ValueType&
value=ValueType()):_previous(0),_next(0),_value(value)
{}
};
template<typename ValueType>
struct ListIndex
{
public:
friend struct ListNode<ValueType>;
friend struct List<ValueType>;
ListNode<ValueType>* _listnode;
public:
ListIndex():_listnode(0)
{}
ListIndex(ListNode<ValueType>* plistnode):_listnode(plistnode)
{}
ListIndex(const ListIndex&
listindex):_listnode(listindex._listnode)
{}
bool operator==(const ListIndex& listindex) const
{
return _listnode==listindex._listnode;
}
bool operator!=(const ListIndex& listindex) const
{
return _listnode!=listindex._listnode;
}
ListIndex& operator++()
{
_listnode=_listnode->_next;
return *this;
}
ListIndex& operator--()
{
_listnode=_listnode->_previous;
return *this;
}
ListIndex& operator=(ListNode<ValueType>* plistnode)
{
_listnode=plistnode;
return *this;
}
ListIndex& operator=(const ListIndex& listindex)
{
if(this!=&listindex)
{
_listnode=listindex._listnode;
}
return *this;
}
};
/**
* @endcond
*/
template<typename ValueType>
/**
* @brief Doubly linked list
*
* Easier than std::list
*
* @author P. Areias
* @version 0.01
*/
struct List
{
public:
/**
* @brief index type
*/
typedef ListIndex<ValueType> Index;
private:
ListNode<ValueType>* _start;
ListNode<ValueType>* _finish;
int _numberofelements;
ListNode<ValueType>* _insertafter(ListNode<ValueType>*
ilistnode,ListNode<ValueType>* alistnode)
{
assert(alistnode);
_numberofelements++;
if(ilistnode==0)
{
assert(_finish==0&&_start==0);
_start=alistnode;
_finish=alistnode;
alistnode->_previous=0;
alistnode->_next=0;
}
else
{
alistnode->_previous=ilistnode;
alistnode->_next=ilistnode->_next;
if(ilistnode->_next==0)
{
_finish=alistnode;
}
else
{
ilistnode->_next->_previous=alistnode;
}
ilistnode->_next=alistnode;
}
return alistnode;
}
ListNode<ValueType>* _insertbefore(ListNode<ValueType>*
ilistnode,ListNode<ValueType>* alistnode)
{
assert(alistnode);
_numberofelements++;
if(ilistnode==0)
{
assert(_finish==0&&_start==0);
_start=alistnode;
_finish=alistnode;
alistnode->_previous=0;
alistnode->_next=0;
}
else
{
alistnode->_previous=ilistnode->_previous;
alistnode->_next=ilistnode;
if(ilistnode->_previous==0)
{
_start=alistnode;
}
else
{
ilistnode->_previous->_next=alistnode;
}
ilistnode->_previous=alistnode;
}
return alistnode;
}
public:
/**
* @brief starting index
* @return starting index
*/
Index start() const
{
Index temp;
temp._listnode=_start;
return temp;
}
/**
* @brief finish index
* @return finish index (valid)
*/
Index finish() const
{
Index temp;
temp._listnode=_finish;
return temp;
}
/**
* @brief tests if an index is valid
* @param index index to test
*/
bool valid(const Index& index) const
{
return index._listnode;
}
/**
* @brief destroys the content at an index
* @param index index to destroy
*/
void destroy(Index& index)
{
auto listnode=index._listnode;
assert(listnode);
_numberofelements--;
if(listnode->_previous==0)
{
_start=listnode->_next;
}
else
{
listnode->_previous->_next=listnode->_next;
}
if(listnode->_next==0)
{
_finish=listnode->_previous;
}
else
{
listnode->_next->_previous=listnode->_previous;
}
delete listnode;
index._listnode=0;
}
/**
* @brief destroys all content
*/
void destroy()
{
for(auto it=start(); valid(it);)
{
auto jt=it;
++jt;
delete it._listnode;
it._listnode=0;
it=jt;
}
_numberofelements=0;
_start=0;
_finish=0;
}
/**
* @brief default constructor
*/
List():_start(0),_finish(0),_numberofelements(0)
{}
/**
* @brief copy constructor
*/
List(const List<ValueType>&
otherlist):_start(0),_finish(0),_numberofelements(0)
{
each(it,otherlist)
{
insertafter(finish(),otherlist(it));
}
}
/**
* @brief initializer list constructor
*/
List(initializer_list<ValueType>
initializerlist):_start(0),_finish(0),_numberofelements(0)
{
foreach(it,initializerlist)
{
insertafter(finish(),*it);
}
}
virtual ~List()
{
destroy();
}
/**
* @brief function call operator
* @param index the position
* @return a reference to the contents at index
*/
ValueType& operator()(const Index& index)
{
assert(valid(index));
return index._listnode->_value;
}
/**
* @brief constant function call operator
* @param index the position
* @return a constant reference to the contents at index
*/
const ValueType& operator()(const Index& it) const
{
assert(it._listnode);
return it._listnode->_value;
}
/**
* @brief assignment operator
* @param otherarray another array
* @return the object
*/
List& operator=(const List<ValueType>& other)
{
if(this!=&other)
{
destroy();
each(it,other)
{
insertafter(finish(),other(it));
}
}
return *this;
}
/**
* @brief assignment operator
* @param initializerlist an initializer list
* @return the object
*/
List& operator=(initializer_list<ValueType> other)
{
destroy();
foreach(it,other)
{
insertafter(finish(),*it);
}
return *this;
}
/**
* @brief inserts a value after a given index
* @param index an index
* @param value the value to insert
* @return the new index
*/
Index insertafter(const Index& index,const ValueType& value)
{
auto listnode=_insertafter(index._listnode,new
ListNode<ValueType>(value));
ListIndex<ValueType> secondindex;
secondindex._listnode=listnode;
return secondindex;
}
/**
* @brief inserts a value before a given index
* @param index an index
* @param value the value to insert
* @return the new index
*/
Index insertbefore(const Index& index,const ValueType& value)
{
auto listnode=_insertbefore(index._listnode,new
ListNode<ValueType>(value));
ListIndex<ValueType> secondindex;
secondindex._listnode=listnode;
return secondindex;
}
/**
* Output ASCII
* @param os output stream
* @param quantity a given list
*/
friend ostream& operator<<(ostream& os,const List<ValueType>&
quantity)
{
os<<quantity._numberofelements<<endl;
each(it,quantity)
os<<quantity(it)<<" ";
os<<endl;
return os;
}
/**
* Input ASCII
* @param is input stream
* @param quantity a given list
*/
friend istream& operator>>(istream& is,List<ValueType>& quantity)
{
quantity.destroy();
int dim;
is>>dim;
for(int it=0; it!=dim; ++it)
{
ValueType val;
is>>val;
quantity.insertafter(quantity.finish(),val);
}
return is;
}
/**
* Output BINARY
* @param os output file
* @param quantity a given list
*/
friend void writing(fstream& os,const List<ValueType>& quantity)
{
writing(os,quantity._numberofelements);
each(it,quantity)
{
writing(os,quantity(it));
}
}
/**
* Input BINARY
* @param is input file
* @param quantity a given list
*/
friend void reading(fstream& is,List<ValueType>& quantity)
{
quantity.destroy();
int dim;
reading(is,dim);
for(int it=0; it!=dim; ++it)
{
ValueType val;
reading(is,val);
quantity.insertafter(quantity.finish(),val);
}
}
};
}
On Feb 13, 7:30 am, Mathias Gaunard <loufo...@gmail.com> wrote:
On Feb 12, 8:26 pm, Carlos Moreno <moreno_n...@mailinator.com> wrote:
On 12-02-11 07:37 PM, Mathias Gaunard wrote:
I've failed to
demonstrate that std::vector is faster than our internal one.
Unfortunately my profiling uniformly suggests std::vector is 10%
slower,
That must mean that your custom vector class is not doing the same
thing as std::vector, simply.
For example std::vector initializes everything you put inside, which
might not be your case. If your own vector doesn't initialize things,
it also means it's unusable with types that are not PODs.
Hopefully you meant the opposite
I didn't.
I don't understand what you're saying. POD stands for Plain Old Data,
types that do not have custom constructors, destructors, nor
assignment operators.
If your code does not call constructors, as std::vector does, then it
only works with POD types, and therefore is unusable with types that
are not PODs.
Bear in mind std::vector allocates memory then use placement new to
copy-construct elements. It does not use 'new' nor default
constructors (it does call it once when resizing/constructing if not
given an explicit value, but only once and then copies).
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]