getting a linker error as already defined operator - c++

i am seeing the linker error so need your help.
i have X.dll in which i have a class called DBFieldBase. in my workspace X i am using vector for some data base related applications. the vector which i am using is from thirdparty ospace.
now i am trying to use vector in one more workspace Y. I added the corresponding include files and .lib files in linker->input option in visual studio 2010.
I did dllexport for workspace X and to use it in Y i am using dllimport.
The error which i am getting is given below
X.lib(X.dll) : error LNK2005: "public: class DBFieldBase * &
__thiscall vector::operator[](unsigned int)" (??A?$vector#PAVDBFieldBase####QAEAAPAVDBFieldBase##I#Z) already
defined in sdb.obj
I dont know exactly what is causing this error. The same code was getting successfully compiled in VS 6.0 now i am trying to build it in VS2010. Please let me know if i am missing anything or so.
Thanks in advance.
P.S. I tried to search the solution on internet for similar problem but unfortunately no success.
the code for vector which is from third party is given below:
class os_vector
{
public:
typedef T value_type;
typedef OS_REFERENCE( T ) reference;
typedef OS_CONST_REFERENCE( T ) const_reference;
typedef OS_SIZE_TYPE( T ) size_type;
typedef OS_DIFF_TYPE( T ) difference_type;
typedef OS_ALLOCATOR( T ) allocator_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T* iterator;
typedef const T* const_iterator;
typedef os_reverse_iterator
<
T*,
T,
OS_REFERENCE( T ),
T*,
OS_DIFF_TYPE( T )
> reverse_iterator;
typedef os_reverse_iterator
<
const T*,
T,
OS_CONST_REFERENCE( T ),
const T*,
OS_DIFF_TYPE( T )
> const_reverse_iterator;
// Construct me to be an empty vector.
os_vector() :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_()
{
}
// Construct me to be an empty vector.
explicit os_vector( const OS_ALLOCATOR( T ) & alloc ) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( alloc )
{
}
// Construct me to contain `n` ( >0 ) elements. Each element will be
// a copy of `value`.
os_vector
(
size_type n,
const T& value, // = T()
const OS_ALLOCATOR( T ) & alloc // = OS_ALLOCATOR( T )()
) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( alloc )
{
assign( n, value );
}
os_vector ( size_type n, const T& value ) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_()
{
assign( n, value );
}
os_vector ( size_type n ) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_()
{
assign( n, T() );
}
// Construct me to contain copies of all the elements in `original`.
os_vector( const os_vector OS_ALLOCATE_ARG_2( T, Allocator ) & original ) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( original.get_allocator() )
{
assign( original.begin(), original.end() );
}
// Construct me to contain all of the elements in the
// range [`first`, `last`).
template< class InIt >
os_vector
(
InIt first,
InIt last,
const OS_ALLOCATOR( T ) & alloc = OS_ALLOCATOR( T )()
) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( alloc )
{
assign( first, last );
}
// Destroy me.
~os_vector()
{
clear();
}
// Replace my contents with a copy of the elements in `original`,
// resizing if necessary.
os_vector OS_ALLOCATE_ARG_2( T, Allocator ) & operator=
(
const os_vector OS_ALLOCATE_ARG_2( T, Allocator ) & original
);
// Remove all my current elements, and then insert the elements
// in range [`first`, `last`).
void assign( const_iterator first, const_iterator last )
{
if ( first == begin() )
erase( begin() + ( last - first ), end() );
else
assign_aux( first, last );
}
// Remove all my current elements, and then insert the elements
// in range [`first`, `last`).
template< class InIt >
void assign( InIt first, InIt last )
{
assign_aux( first, last );
}
// Remove all my current elements, and then insert `n` copies of
// `value`.
void assign( size_type n, const T& value );
void assign( size_type n )
{
assign( n, T() );
}
// Return a copy of the allocator I am using.
allocator_type get_allocator() const
{
return alloc_;
}
// Return a random access iterator positioned at my first element.
iterator begin()
{
return start_;
}
// Return a constant random access iterator positioned at my first
// element.
const_iterator begin() const
{
return start_;
}
// Return a random access iterator positioned immediately after my
// last element.
iterator end()
{
return finish_;
}
// Return a constant random access iterator positioned immediately after
// my last element.
const_iterator end() const
{
return finish_;
}
// Return a random access reverse iterator positioned immediately after
// my last element.
reverse_iterator rbegin()
{
return reverse_iterator( end() );
}
// Return a constant random access reverse iterator positioned
// immediately after my last element.
const_reverse_iterator rbegin() const
{
return const_reverse_iterator( end() );
}
// Return a random access reverse iterator positioned at my first
// element.
reverse_iterator rend()
{
return reverse_iterator( begin() );
}
// Return a constant random access reverse iterator positioned at my
// first element.
const_reverse_iterator rend() const
{
return const_reverse_iterator( begin() );
}
// Return the number of elements that I contain.
size_type size() const
{
return end() - begin();
}
// Return the maximum number of elements that I can contain.
size_type max_size() const
{
return alloc_.max_size();
}
// Cause myself to hold `n` elements, using `value` to expand
// myself if necessary.
void resize( size_type n, T value )
{
if ( n > size() )
insert( end(), n - size(), value );
else
erase( begin() + n, end() );
}
// Cause myself to hold `n` elements using the default constructor
// to expand myself if necessary.
void resize( size_type n )
{
resize( n, T() );
}
// Return the number of elements that I can contain without allocating
// more memory.
size_type capacity() const
{
return end_of_storage_ - start_;
}
// Return true if I contain no elements.
bool empty() const
{
return begin() == end();
}
// Change my capacity to be at least `n`. Does not affect my
// current size.
void reserve( size_type n );
// Return a reference to my `n`th element.
reference operator[]( size_type n )
{
OS_ASSERT_NOT_EMPTY( empty() )
OS_ASSERT_INDEX_OK( n, 0, size() - 1 )
return *( begin() + n );
}
// Return a constant reference to my `n`th element.
const_reference operator[]( size_type n ) const
{
OS_ASSERT_NOT_EMPTY( empty() )
OS_ASSERT_INDEX_OK( n, 0, size() - 1 )
return *( begin() + n );
}
// Return a reference to my `n`th element.
reference at( size_type n )
{
if ( n >= size() )
os_throw_out_of_range();
return *( begin() + n );
}
// Return a constant reference to my `n`th element.
const_reference at( size_type n ) const
{
if ( n >= size() )
os_throw_out_of_range();
return *( begin() + n );
}
// Return a reference to my first element.
reference front()
{
OS_ASSERT_NOT_EMPTY( empty() )
return *begin();
}
// Return a constant reference to my first element.
const_reference front() const
{
OS_ASSERT_NOT_EMPTY( empty() )
return *begin();
}
// Return a reference to my last element.
reference back()
{
OS_ASSERT_NOT_EMPTY( empty() )
return *( end() - 1 );
}
// Return a constant reference to my last element.
const_reference back() const
{
OS_ASSERT_NOT_EMPTY( empty() )
return *( end() - 1 );
}
// Add `value` at my end.
void push_back( const_reference value )
{
if ( finish_ != end_of_storage_ )
{
alloc_.construct( finish_, value );
++finish_;
}
else
insert_aux( end(), value );
}
// Erase my last element.
void pop_back()
{
OS_ASSERT_NOT_EMPTY_ELSE( empty() )
{
--finish_; // not on a single line due to Borland problem
alloc_.destroy( finish_ );
}
}
// Insert `value` at `pos` and return an iterator pointing to the new
// element's position.
iterator insert( iterator pos, const T& value )
{
size_type n = pos - begin();
if ( finish_ != end_of_storage_ && pos == finish_ )
{
alloc_.construct( finish_, value );
++finish_;
}
else
insert_aux( pos, value );
return begin() + n;
}
// Insert an element constructed with the default constructor at `pos` and
// return an iterator pointing to the new element's position.
// not standard, left for backward compatibility
iterator insert( iterator pos )
{
return insert( pos, T() );
}
// Insert `n` copies of `value` at `pos`.
void insert( iterator pos, size_type n, const T& value );
// Insert copies of the elements in range [`first`, `last`) at `pos`.
template< class InIt >
void insert( iterator pos, InIt first, InIt last );
// Erase the element at `pos`.
iterator erase( iterator pos )
{
if ( !( pos + 1 == end() ) )
copy( pos + 1, end(), pos );
pop_back();
return pos;
}
// Erase the elements in range [`first`, `last`).
iterator erase( iterator first, iterator last )
{
iterator i = copy( last, end(), first );
destroy( i, finish_, alloc_ );
finish_ = finish_ - ( last - first );
return first;
}
// Swap my contents with those of `original`.
void swap( os_vector OS_ALLOCATE_ARG_2( T, Allocator ) & original )
{
if ( !(alloc_ == original.alloc_ ) )
{
os_vector OS_ALLOCATE_ARG_2( T, Allocator ) tmp( *this );
assign( original.begin(), original.end() );
original.assign( tmp.begin(), tmp.end() );
}
else
{
::swap( start_, original.start_ );
::swap( finish_, original.finish_ );
::swap( end_of_storage_, original.end_of_storage_ );
::swap( alloc_, original.alloc_ );
}
}
// Erase all of my elements.
void clear()
{
if ( start_ )
{
destroy( start_, finish_, alloc_ );
alloc_.deallocate( start_ );
}
start_ = finish_ = end_of_storage_ = 0;
}
protected:
void insert_aux( T* pos, const T& value );
template< class InIt >
void assign_aux( InIt first, InIt last );
private:
// Data members.
iterator start_;
iterator finish_;
iterator end_of_storage_;
allocator_type alloc_;
public:
// Construct me to contain n ( >0 ) elements. Each element will be
// default constructed.
// This remains for compatibility. It will be removed in a future release.
os_vector
(
const OS_ALLOCATOR( T ) & alloc,
size_type n
) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( alloc )
{
assign( n, T() );
}
// Construct me to contain n ( >0 ) elements. Each element will be
// a copy of `value`.
// This remains for compatibility. It will be removed in a future release.
os_vector
(
const OS_ALLOCATOR( T ) & alloc,
size_type n,
const T& value
) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( alloc )
{
assign( n, value );
}
// Construct me to contain copies of all the elements in `original`.
// This remains for compatibility. It will be removed in a future release.
os_vector
(
const OS_ALLOCATOR( T ) & alloc,
const os_vector OS_ALLOCATE_ARG_2( T, Allocator ) & original
) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( alloc )
{
assign( original.begin(), original.end() );
}
// Construct me to contain all of the elements in the
// range [`first`, `last`).
// This remains for compatibility. It will be removed in a future release.
os_vector
(
const OS_ALLOCATOR( T ) & alloc,
const_iterator first,
const_iterator last
) :
start_( 0 ),
finish_( 0 ),
end_of_storage_( 0 ),
alloc_( alloc )
{
assign( first, last );
}
// Erase all of my elements.
// This remains for compatibility. It will be removed in a future release.
void erase()
{
clear();
}
};
in X.DLL i have a class DBFieldBase its like our our normal class with member variables and functions.
in Y workspace in one of the class i am using vector that usage is given below:
private:
vector < DBFieldBase *> & GetASDVect (void);
vector <DBFieldBase *> m_ASDVect;
Then outside class in same header file there is definition for GetASDVect. its inline
inline vector <DBFieldBase *> & ASD_sdb::GetASDVect (void)
{
return this->m_ASDVect;
}
Let me know if you need anything else from my side.

You've defined a symbol multiple times. I guess a symbol is defined in both X.dll and Y.dll ?

Related

how can i create a binary search in a linked List? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
This is an assignment for a class, for this program i need to implement a binary search for linked List, how can i do that? is it possible to determine and access the middle element of a list, and proceed with focus on only the left or
right half of the list?
how can i implement binary search for linked list?
Searching.h
#ifndef SEARCHING_H_
#define SEARCHING_H_
#include "Vector.h"
#include "List.h"
using namespace std;
template <typename T>
void print_vector(const Vector<T>& vec)
{
for (int i = 0; i < vec.size(); i++)
cout << vec[i] << " ";
cout << endl;
return;
}
// LINEAR SEARCH OF VECTOR
// return index at which target found, if not found return -1;
template <typename T>
int linear_search_V(const Vector<T>& vec, const T& target, int& ops)
{
ops = 0;
for (int i = 0; i < vec.size(); i++) {
ops++;
if (vec[i] == target)
return i;
}
return -1;
}
// LINEAR SEARCH OF LINKED LIST
// return iterator to node at which target
// found in lst; else return iterator at end() of lst;
template <typename T>
typename List<T>::const_iterator linear_search_L(const List<T>& lst, const T& target, int& ops)
{
ops = 0;
typename List<T>::const_iterator itr;
for (itr = lst.begin(); itr != lst.end(); ++itr) {
ops++;
if (*itr++ == target)
return itr;
}
return lst.end();
}
// BINARY SEARCH OF VECTOR;
// returns index at which target found, else -1;
template <typename T>
int binary_search_V(const Vector<T>& vec, const T& target, int& ops)
{
ops = 0;
int low = 0;
int high = vec.size() - 1;
while (low <= high) {
ops++;
int mid = (low + high) / 2;
if (vec[mid] < target)
low = mid + 1;
else if (vec[mid] > target)
high = mid - 1;
else
return mid;
}
return -1;
}
// BINARY SEARCH OF LINKED LIST
// returns iterator at target value found; iterator end() else;
template <typename T>
typename List<T>::const_iterator binary_search_L(const List<T> lst, const T& target, int& ops)
{
ops = 0;
//implement function for binary search in Linked List:
}
#endif
//this is the List.h i need to use for the binary search in a linked list
#ifndef LIST_H
#define LIST_H
//#include <algorithm>
using namespace std;
template <typename T>
class List
{
private:
// The basic doubly linked list node.
// Nested inside of List, can be public
// because the Node is itself private
struct Node
{
T data;
Node *prev;
Node *next;
Node( const T & d = T{ }, Node * p = nullptr, Node * n = nullptr )
: data{ d }, prev{ p }, next{ n } { }
Node( T && d, Node * p = nullptr, Node * n = nullptr )
: data{ std::move( d ) }, prev{ p }, next{ n } { }
};
public:
class const_iterator
{
public:
// Public constructor for const_iterator.
const_iterator( ) : current{ nullptr }
{ }
// Return the T stored at the current position.
// For const_iterator, this is an accessor with a
// const reference return type.
const T & operator* ( ) const
{ return retrieve( ); }
const_iterator & operator++ ( )
{
current = current->next;
return *this;
}
const_iterator operator++ ( int )
{
const_iterator old = *this;
++( *this );
return old;
}
const_iterator & operator-- ( )
{
current = current->prev;
return *this;
}
const_iterator operator-- ( int )
{
const_iterator old = *this;
--( *this );
return old;
}
bool operator== ( const const_iterator & rhs ) const
{ return current == rhs.current; }
bool operator!= ( const const_iterator & rhs ) const
{ return !( *this == rhs ); }
// iterators side-by-side
bool operator > (const const_iterator & rhs) const
{
return current->prev == rhs.current;
}
protected:
Node *current;
// Protected helper in const_iterator that returns the T
// stored at the current position. Can be called by all
// three versions of operator* without any type conversions.
T & retrieve( ) const
{ return current->data; }
// Protected constructor for const_iterator.
// Expects a pointer that represents the current position.
const_iterator( Node *p ) : current{ p }
{ }
friend class List<T>;
};
class iterator : public const_iterator
{
public:
// Public constructor for iterator.
// Calls the base-class constructor.
// Must be provided because the private constructor
// is written; otherwise zero-parameter constructor
// would be disabled.
iterator( )
{ }
T & operator* ( )
{ return const_iterator::retrieve( ); }
.
const T & operator* ( ) const
{ return const_iterator::operator*( ); }
iterator & operator++ ( )
{
this->current = this->current->next;
return *this;
}
iterator operator++ ( int )
{
iterator old = *this;
++( *this );
return old;
}
iterator & operator-- ( )
{
this->current = this->current->prev;
return *this;
}
iterator operator-- ( int )
{
iterator old = *this;
--( *this );
return old;
}
protected:
// Protected constructor for iterator.
// Expects the current position.
iterator( Node *p ) : const_iterator{ p }
{ }
friend class List<T>;
};
public:
List( )
{ init( ); }
~List( )
{
clear( );
delete head;
delete tail;
}
List( const List & rhs )
{
init( );
for( auto & x : rhs )
push_back( x );
}
List & operator= ( const List & rhs )
{
List copy = rhs;
std::swap( *this, copy );
return *this;
}
// keep for compiler
List(List&& rhs)
: theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail }
{
rhs.theSize = 0;
rhs.head = nullptr;
rhs.tail = nullptr;
}
// keep for compiler
List& operator= (List&& rhs)
{
std::swap(theSize, rhs.theSize);
std::swap(head, rhs.head);
std::swap(tail, rhs.tail);
return *this;
}
// Return iterator representing beginning of list.
// Mutator version is first, then accessor version.
iterator begin( )
{ return iterator( head->next ); }
const_iterator begin( ) const
{ return const_iterator( head->next ); }
// Return iterator representing endmarker of list.
// Mutator version is first, then accessor version.
iterator end( )
{ return iterator( tail ); }
const_iterator end( ) const
{ return const_iterator( tail ); }
// Return number of elements currently in the list.
int size( ) const
{ return theSize; }
// Return true if the list is empty, false otherwise.
bool empty( ) const
{ return size( ) == 0; }
void clear( )
{
while( !empty( ) )
pop_front( );
}
// front, back, push_front, push_back, pop_front, and pop_back
// are the basic double-ended queue operations.
T & front( )
{ return *begin( ); }
const T & front( ) const
{ return *begin( ); }
T & back( )
{ return *--end( ); }
const T & back( ) const
{ return *--end( ); }
void push_front( const T & x )
{ insert( begin( ), x ); }
void push_back( const T & x )
{ insert( end( ), x ); }
void pop_front( )
{ erase( begin( ) ); }
void pop_back( )
{ erase( --end( ) ); }
// Insert x before itr.
iterator insert( iterator itr, const T & x )
{
Node *p = itr.current;
++theSize;
return iterator( p->prev = p->prev->next = new Node{ x, p->prev, p } );
}
// Erase item at itr.
iterator erase( iterator itr )
{
Node *p = itr.current;
iterator retVal( p->next );
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
--theSize;
return retVal;
}
iterator erase( iterator from, iterator to )
{
for( iterator itr = from; itr != to; )
itr = erase( itr );
return to;
}
private:
int theSize;
Node *head;
Node *tail;
void init( )
{
theSize = 0;
head = new Node;
tail = new Node;
head->next = tail;
tail->prev = head;
}
};
#endif
It is not meaningful to use binary search on a linked list, as random access has a prohibitively high time complexity in a linked list. In a singly-linked list, on average, half of the list must be traversed on every random access. This is the same amount of work that a simple linear search would need for performing the entire search, on average.
Instead of arranging your nodes in a linked list where every node is linked with up to one other node, it would make more sense to arrange your nodes in a tree, where every node is linked with up to two other nodes. I recommend arranging them in a binary search tree, as that is an ideal data structure for a binary search.
A binary search on a linked list is an odd concept, but let's hold off on the oddity for the moment. To start, let's adapt the binary search algorithm to the linked list interface.
To start a binary search, you need the middle of the list. So first you need to know how long your list is. If the list had not stored its size, the size could be determined by iterating over the list, counting nodes as you proceed. Once you have the size, you divide by 2 as normal. Also, cache a copy of the pointer to the head of the list, for a reason that will become clear later.
Once you know which node you need, you start with your cached head pointer and advance that many nodes. If you found the desired node, you are done. If the middle node is too low, replace your cached head pointer with a pointer to the midpoint node (which has become the new low end of your search). In either case (too low or too high), divide the index of the node you had looked for by two and repeat.
Note: the code for this might very well look complicated and/or messy, especially when compared to the vector version.
Well, the above also needs a check to for "not found". There is probably also some round-off error to deal with. While these are important, I'd rather look at why one might want to do this. (Besides, working on those details might be useful practice. You still have to do some work for your assignment. ;) )
How effective is this binary search compared to a linear search for a list of length n? A linear search will, on average compare n/2 nodes and follow n/2 links. A binary search, on the other hand, will on average compare lg n nodes and follow n links (or something more like n lg n links if you do not cache the starting point). Perhaps more striking is that a binary search will at minimum follow n/2 links (to get to the first midpoint), which is average for a binary search. How could a binary search hope to ever be better than linear?
One possibility lies in the number of comparisons. If comparing nodes is particularly expensive, the reduced number of comparisons could (in theory) make up for the increased amount of walking through the list. I don't know any examples of when this comes into play, but I'll grant the possibility. Theoretically.
What I find more likely is that you were given this assignment to drive home the point that you do not want to do a binary search on a linked list. Drive home the idea that if you need to do a binary search, you'll want a container (like a vector) that provides random access to its elements. Use the right tool for the job at hand.

How would one write a custom Vector method to delete an element without using vector::erase()?

I'm writing a custom vector class, and I need to have an erase function without actually using vector::erase();
I need the same functionality, using only what I can write along with a few other pre-completed methods such as resize(), reserve(), pop, and push_back. The only parameter it takes is an iterator. My vector specifically is holding a bunch of lists. The element pointed to by the iterator should be deleted, and the rest of the vector left the same.
Here are some of the methods I have already:
void resize( int newSize )
{
if( newSize > theCapacity )
reserve( newSize * 2 );
theSize = newSize;
}
void reserve( int newCapacity )
{
if( newCapacity < theSize )
return;
Object *newArray = new Object[ newCapacity ];
for( int k = 0; k < theSize; ++k )
newArray[ k ] = std::move( objects[ k ] );
theCapacity = newCapacity;
std::swap( objects, newArray );
delete [ ] newArray;
}
// Stacky stuff
void push_back( const Object & x )
{
if( theSize == theCapacity )
reserve( 2 * theCapacity + 1 );
objects[ theSize++ ] = x;
}
// Stacky stuff
void push_back( Object && x )
{
if( theSize == theCapacity )
reserve( 2 * theCapacity + 1 );
objects[ theSize++ ] = std::move( x );
}
void pop_back( )
{
if( empty( ) )
throw UnderflowException{ };
--theSize;
}
Is such a thing possible?
Typically std::vector::erase manually calls the dtor, uses placement new to copy construct (or move construct, if available) the elements into that gap, and then modifies the end iterator.
A simple implementation with iterators:
void erase(Iterator<Object> it) {
while (next(it) != end()) {
*it = *next(it); // or std::move(*next(it))
it = next(it);
}
--theSize;
end()->Object::~Object(); // not necessary -- assumes updated end()
}

How to iterate through a list but stop at size-1

This code:
for (std::list<point>::const_iterator it = controlPoints->begin();
it != controlPoints->end();
++it) {
...
}
Corresponds to:
for (int i = 0; i < controlPoints->size; i++) {
...
}
Meaning, it would iterate through all elements of the list if I got one element for each time it looped.
What would correspond to:
for (int i = 0; i < controlPoints->size-1; i++) {
...
}
I mean, how can I loop size-1 times using iterators?
The obvious way would be to get an iterator to the end and decrement it:
auto stop = controlPoints.end();
--stop;
for (std::list<point>::const_iterator it = controlPoints->begin();
it != stop;
++it) {
...
}
You could use std::advance or std::next if you preferred, but for this case a simple decrement is fine.
controlPoints->end() is also an iterator.
You could do this:
std::list<point>::const_iterator it = controlPoints->begin();
std::list<point>::const_iterator stop = controlPoints->end();
if ( it != stop) for ( --stop; it != stop; ++it) {
...
}
More verbose but it's safe to use whether the list has 0, 1 or more elements.
The key here is that iterators can be incremented and (for bidirectional iterators) decremented to advance / recede the position, so it's the equivalent of doing:
int it = 0;
int stop = list.size();
if (it != stop) for( --stop; it < stop; ++it ) {
...
}
In C++11 you should seek to use the ranged based for loop as often as you can. for(;;) loops are complex and error prone at the point you write them.
Using for(:) loops requires complexity away from the point you write them, but because you can write that infrastructure once and reuse it the bugs in it can be ironed out, instead of being dispursed throughout the code.
To start with, here is a simple range_t:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
std::size_t size() const { return std::distance(begin(), end()); }
using iterator_tag = typename std::iterator_traits<It>::iterator_category;
private:
static It safe_advance( It in, It bound, std::ptrdiff_t n, std::random_access_iterator_tag ) const {
if (n == 0) return in;
if (n < 0) n = (std::min)( n, -std::distance( bound, in ) );
if (n > 0) n = (std::max)( n, std::distance( in, bound ) );
return std::advance( in, n );
}
static It safe_advance( It in, It bound, std::ptrdiff_t n, ... ) const {
if (n == 0) return in;
while (n < 0 && in != bound) {
in = std::prev(in); --n;
}
while (n > 0 && in != bound) {
in = std::next(in); ++n;
}
return in;
}
public:
range_t without_back( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), -(std::ptrdiff_t)n, iterator_tag{} };
}
range_t without_front( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), n, iterator_tag{} };
}
bool empty() const { return begin() == end(); }
decltype(auto) front() const { return *begin(); }
decltype(auto) back() const { return *std::prev(end()); }
};
template<class It>
range_t<It> range( It b, It e ) { return {b,e}; }
// rvalues blocked:
template<class C, class It = decltype( std::begin(std::declval<C&>()) )>
range_t<It> range( C& c ) { return range( std::begin(c), std::end(c) ); }
it stores a range of iterators and is itself iterable.
Then:
auto r = range(*controlPoints).without_back();
is a range object that is the controlPoints without the last element.
Using ranged-based for you can do this:
for (auto& x : range(*controlPoints).without_back()) {
}
note that the above code carefully handles being fed an empty array.
We can also write a similar adapter that lets you iterator over the iterators. I usually do this by writing an index_iterator that stores an Index and passes ++ and == etc to it. Except when you * it simply returns a copy of the Index.
This is useful to create an iterator over integers, but also lets you create an iterator over iterators.
Then create a range of indexes to the iterators in your container, and you get syntax that looks like:
for (auto it : iterators_into( *controlPoints) ) {
}
giving you range-based loops that also gives you iterators if you need them.

How to define an common iterator to my class hirerachy

My team designed a library meant to store data from different "signals". A signal is a list of timestamped float values. We have three way to store a signal (depending of the way it was recorded from the hardware in the first place):
MarkerSignal: We store a sorted std::vector of std::pair of (boost::posix_time::ptime,float)
RawSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration) and finally a std::vector of float (each value's timestamp is start time + period * value's index in the vector)
NumericalSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration), a scale (float), an offset (float) and finally a std::vector of short (timestamp is computed as for RawSignal and float value is short*scale+offset)
Those three signals have a common parent class (SignalBase) storing the signal's name, description, unit and stuff like that. We use the visitor pattern to let people nicely "cast" the SignalBase to a MarkerSignal/RawSignal/NumericalSignal and then access the data it contains.
In the end, what we need for each class is to iterate through all elements, one element being actually a pair of (boost::posix_time::ptime,float) (like MarkerSignal). And it's a pain having to create a visitor every time we want to do that.
Storing all signals as a std::vector<std::pair<boost::posix_time::ptime,float>> (or returning an object of this kind on demand) uses too much memory.
We thought the best was probably to define our own iterator object. The iterator would give access to the timestamp and value, like that:
SignalBase* signal = <any signal>;
for ( SignalBase::iterator iter = signal->begin();
iter != signal->end();
++iter )
{
boost::posix_time::ptime timestamp = iter.time();
float value = iter.value();
}
What's the best approach/strategy to create such an iterator class? (simple class with a size_t index attribute, or a MarkerSignal/RawSignal/NumericalSignal container's specific iterator as attribute, store a std::pair<boost::posix_time::ptime,float> and update it from a ++ operator...).
Also, I would much prefer if the solution rpoposed avoids using a virtual table (to have ++, time(), and value() be faster when iterating on huge signals).
To sum up I think the best you can achieve if you value for efficiency could be something like this:
template <typename SignalType, typename Functor = function<void(typename SignalType::value_type&&) > >
void iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
Then for call:
iterateThroughSignal<MarkerSignal>(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
I'm not sure if you are using C++11 so the lambda can be replace by function pointer, rvalue reference using lvalue reference and the std::function with a function signature...
Edit:
To make it compile when the type of the foo signature won't match the SignalType::value_type there will be a need of playing a little bit with sfinae:
template <typename SignalType>
class IterateHelper {
template <typename Functor>
static typename enable_if<first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
template <typename Functor>
static typename enable_if<!first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
}
};
I leave the implementation of first_param_is helper struct to you... Call would change to:
IteratorHelper<MarkerSignal>::iterateThroughSignal(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
As I wanted something easy to use for people using my library (be able to esily do a for loop) I finally implemented my own iterator like that:
Added two virtual functions in SignalBase (found no alternative to that, runtime will use the virtual table):
virtual size_t floatDataCount() const = 0;
virtual bool loadFloatInfoAt( size_t pos, SignalFloatIter::ValueInfo& info ) const = 0;
Added functions in SignalBase to get begin/end iterators:
inline BDL::SignalFloatIter beginFloatIter() const { return BDL::SignalFloatIter::beginIter( *this ); }
inline BDL::SignalFloatIter endFloatIter() const { return BDL::SignalFloatIter::endIter( *this ); }
Declared iterator class like that:
class SignalFloatIter
{
public:
SignalFloatIter( const SignalBase* signal = NULL, size_t pos = 0 );
SignalFloatIter( const SignalFloatIter& iter );
static SignalFloatIter beginIter( const SignalBase& signal );
static SignalFloatIter endIter( const SignalBase& signal );
SignalFloatIter& operator=( const SignalFloatIter& iter );
bool operator==( const SignalFloatIter& iter ) const;
bool operator!=( const SignalFloatIter& iter ) const;
/** Pre-increment operator */
SignalFloatIter& operator++();
/** Post-increment operator */
SignalFloatIter operator++(int unused);
inline const BDL::time& when() const { assert( m_valid ); return m_info.first.first; }
inline const BDL::duration& duration() const { assert( m_valid ); return m_info.first.second; }
inline const float& value() const { assert( m_valid ); return m_info.second; }
inline size_t index() const { assert( m_valid ); return m_pos; }
inline BDL::MarkerKey markerKey() const { assert( m_valid ); return std::make_pair( when(), duration() ); }
inline bool valid() const { return m_valid; }
typedef std::pair<BDL::time,BDL::duration> TimeInfo;
typedef std::pair<TimeInfo,float> ValueInfo;
private:
const SignalBase* m_signal;
size_t m_pos;
bool m_valid;
ValueInfo m_info;
void loadCurInfo();
};
Implemented:
SignalFloatIter::SignalFloatIter( const SignalBase* signal, size_t pos ) :
m_signal( signal ),
m_pos( pos )
{
loadCurInfo();
}
SignalFloatIter::SignalFloatIter( const SignalFloatIter& iter )
{
operator=( iter );
}
SignalFloatIter SignalFloatIter::beginIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, 0 );
}
SignalFloatIter SignalFloatIter::endIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, signal.floatDataCount() );
}
SignalFloatIter& SignalFloatIter::operator=( const SignalFloatIter& iter )
{
if ( this != &iter )
{
m_signal = iter.m_signal;
m_pos = iter.m_pos;
m_info = iter.m_info;
m_valid = iter.m_valid;
}
return *this;
}
bool SignalFloatIter::operator==( const SignalFloatIter& iter ) const
{
if ( m_signal == iter.m_signal )
{
if ( m_pos == iter.m_pos )
{
assert( m_valid == iter.m_valid );
if ( m_valid )
assert( m_info == iter.m_info );
return true;
}
else
{
return false;
}
}
else
{
assert( false );
return false;
}
}
bool SignalFloatIter::operator!=( const SignalFloatIter& iter ) const
{
return !( *this == iter );
}
SignalFloatIter& SignalFloatIter::operator++()
{
++m_pos;
loadCurInfo();
return *this;
}
SignalFloatIter SignalFloatIter::operator++( int unused )
{
SignalFloatIter old = *this;
assert( unused == 0 ); // see http://en.cppreference.com/w/cpp/language/operator_incdec
++m_pos;
loadCurInfo();
return old;
}
void SignalFloatIter::loadCurInfo()
{
if ( m_signal )
{
m_valid = m_signal->loadFloatInfoAt( m_pos, m_info );
}
else
{
assert( false );
m_valid = false;
}
}
It's pretty straightforward and easy to use for any signal:
std::cout << "Signal timestamped data are: ";
for ( BDL::SignalFloatIter iter = signal.beginFloatIter();
iter != signal.endFloatIter();
++iter )
{
std::cout << iter.when() << " : " << iter.value() << std::endl;
}

Unable to insert more than 256 nodes into a custom tree

I've been stuck on this for quite some time now and have even tested the issue between a 64-bit version of gcc on Ubuntu as welll as a 32-bit gcc on Windows (MinGW).
Any time I insert more than 256 nodes into a binary-tree(?), it stops counting the number of nodes. I can still access all of my data. I have a feeling that it has something to do with the way I have my structure setup, by using chars to acquire each bit of each byte, but I have no idea how to fix it.
In this header, I have a structure and some functions setup which allows me to acquire an individual bit of an object.
This is the actual tree implementation. In order to find where to store each object, the tree iterates through each byte of a key, then iterates again through each bit of those bytes. The "iterate" function is what is giving me the most difficulty though; I have no idea why, but once 256 nodes become filled with data, my structure stops counting further, then begins to replace all previous data. I believe this has something to do with the fact that a single char can only hold 0-256, but I can't see where this would be an issue. Since the location of each node is determined by the individual bits of the key, it's hard to determine why only 256 items can be placed into the tree.
The URL to my test program is at the bottom of the post. SO won't let me post more than 2 at the moment. I would like to get this done soon, so any help would be greatly appreciated.
Edit:
Just to make things easier, this is the structure that gives me the individual bit of a byte, as well as a helper function:
struct bitMask {
char b1 : 1;
char b2 : 1;
char b3 : 1;
char b4 : 1;
char b5 : 1;
char b6 : 1;
char b7 : 1;
char b8 : 1;
char operator[] ( unsigned i ) const {
switch( i ) {
case 0 : return b1;
case 1 : return b2;
case 2 : return b3;
case 3 : return b4;
case 4 : return b5;
case 5 : return b6;
case 6 : return b7;
case 7 : return b8;
}
return 0; // Avoiding a compiler error
}
};
/******************************************************************************
* Functions shared between tree-type objects
******************************************************************************/
namespace treeShared {
// Function to retrieve the next set of bits at the pointer "key"
template <typename key_t>
inline const bitMask* getKeyByte( const key_t* key, unsigned iter );
/* template specializations */
template <>
inline const bitMask* getKeyByte( const char*, unsigned );
template <>
inline const bitMask* getKeyByte( const wchar_t*, unsigned );
template <>
inline const bitMask* getKeyByte( const char16_t*, unsigned );
template <>
inline const bitMask* getKeyByte( const char32_t*, unsigned );
} // end treeShared namespace
/*
* Tree Bit Mask Function
*/
template <typename key_t>
inline const bitMask* treeShared::getKeyByte( const key_t* k, unsigned iter ) {
return (iter < sizeof( key_t ))
? reinterpret_cast< const bitMask* >( k+iter )
: nullptr;
}
/*
* Tree Bit Mask Specializations
*/
template <>
inline const bitMask* treeShared::getKeyByte( const char* str, unsigned iter ) {
return (str[ iter ] != '\0')
? reinterpret_cast< const bitMask* >( str+iter )
: nullptr;
}
template <>
inline const bitMask* treeShared::getKeyByte( const wchar_t* str, unsigned iter ) {
return (str[ iter ] != '\0')
? reinterpret_cast< const bitMask* >( str+iter )
: nullptr;
}
template <>
inline const bitMask* treeShared::getKeyByte( const char16_t* str, unsigned iter ) {
return (str[ iter ] != '\0')
? reinterpret_cast< const bitMask* >( str+iter )
: nullptr;
}
template <>
inline const bitMask* treeShared::getKeyByte( const char32_t* str, unsigned iter ) {
return (str[ iter ] != '\0')
? reinterpret_cast< const bitMask* >( str+iter )
: nullptr;
}
And here is the tree class:
template <typename data_t>
struct bTreeNode {
data_t* data = nullptr;
bTreeNode* subNodes = nullptr;
~bTreeNode() {
delete data;
delete [] subNodes;
data = nullptr;
subNodes = nullptr;
}
};
/******************************************************************************
* Binary-Tree Structure Setup
******************************************************************************/
template <typename key_t, typename data_t>
class bTree {
enum node_dir : unsigned {
BNODE_LEFT = 0,
BNODE_RIGHT = 1,
BNODE_MAX
};
protected:
bTreeNode<data_t> head;
unsigned numNodes = 0;
private:
bTreeNode<data_t>* iterate( const key_t* k, bool createNodes );
public:
~bTree() {}
// STL-Map behavior
data_t& operator [] ( const key_t& k );
void push ( const key_t& k, const data_t& d );
void pop ( const key_t& k );
bool hasData ( const key_t& k );
const data_t* getData ( const key_t& k );
unsigned size () const { return numNodes; }
void clear ();
};
/*
* Binary-Tree -- Element iteration
*/
template <typename key_t, typename data_t>
bTreeNode<data_t>* bTree<key_t, data_t>::iterate( const key_t* k, bool createNodes ) {
node_dir dir;
unsigned bytePos = 0;
bTreeNode<data_t>* bNodeIter = &head;
const bitMask* byteIter = nullptr;
while ( byteIter = treeShared::getKeyByte< key_t >( k, bytePos++ ) ) {
for ( int currBit = 0; currBit < HL_BITS_PER_BYTE; ++currBit ) {
// compare the bits of each byte in k
dir = byteIter->operator []( currBit ) ? BNODE_LEFT : BNODE_RIGHT;
// check to see if a new bTreeNode needs to be made
if ( !bNodeIter->subNodes ) {
if ( createNodes ) {
// create and initialize the upcoming sub bTreeNode
bNodeIter->subNodes = new bTreeNode<data_t>[ BNODE_MAX ];
}
else {
return nullptr;
}
}
// move to the next bTreeNode
bNodeIter = &(bNodeIter->subNodes[ dir ]);
}
}
return bNodeIter;
}
/*
* Binary-Tree -- Destructor
*/
template <typename key_t, typename data_t>
void bTree<key_t, data_t>::clear() {
delete head.data;
delete [] head.subNodes;
head.data = nullptr;
head.subNodes = nullptr;
numNodes = 0;
}
/*
* Binary-Tree -- Array Subscript operators
*/
template <typename key_t, typename data_t>
data_t& bTree<key_t, data_t>::operator []( const key_t& k ) {
bTreeNode<data_t>* iter = iterate( &k, true );
if ( !iter->data ) {
iter->data = new data_t();
++numNodes;
}
return *iter->data;
}
/*
* Binary-Tree -- Push
* Push a data element to the tree using a key
*/
template <typename key_t, typename data_t>
void bTree<key_t, data_t>::push( const key_t& k, const data_t& d ) {
bTreeNode<data_t>* iter = iterate( &k, true );
if ( !iter->data ) {
iter->data = new data_t( d );
++numNodes;
}
else {
*iter->data = d;
}
}
/*
* Binary-Tree -- Pop
* Remove whichever element lies at the key
*/
template <typename key_t, typename data_t>
void bTree<key_t, data_t>::pop( const key_t& k ) {
bTreeNode<data_t>* iter = iterate( &k, false );
if ( !iter || !iter->data )
return;
delete iter->data;
iter->data = nullptr;
--numNodes;
}
/*
* Binary-Tree -- Has Data
* Return true if there is a data element at the key
*/
template <typename key_t, typename data_t>
bool bTree<key_t, data_t>::hasData( const key_t& k ) {
bTreeNode<data_t>* iter = iterate( &k, false );
return iter && ( iter->data != nullptr );
}
/*
* Binary-Tree -- Push
* Return a pointer to the data that lies at a key
* Returns a nullptr if no data exists
*/
template <typename key_t, typename data_t>
const data_t* bTree<key_t, data_t>::getData( const key_t& k ) {
bTreeNode<data_t>* iter = iterate( &k, false );
if ( !iter )
return nullptr;
return iter->data;
}
pastebin.com/8MZ0TMpj
template <typename key_t>
inline const bitMask* treeShared::getKeyByte( const key_t* k, unsigned iter ) {
return (iter < sizeof( key_t ))
? reinterpret_cast< const bitMask* >( k+iter )
: nullptr;
}
This doesn't do what you seem to think it does. (k+iter) doesn't retrieve the iter'th byte of k, but the iter'th element of the key_t[] array pointed to by k. In other words, k+iter advances the pointer by iter*sizeof(key_t) bytes, not by iter bytes.
Formally, this code exhibits undefined behavior, by overrunning array bounds. Practically speaking, your program uses just a single byte of the key, and then sizeof(key_t)-1 random bytes that just happen to sit in memory above that key. That's why you are effectively limited to 8 bits of state.
In addition, your reinterpret_cast also exhibits undefined behavior, formally speaking. The only legal use for a pointer obtained with reinterpret_cast is to reinterpret_cast it right back to the original type. This is not the immediate cause of your problem though.