Today I didn't pass the test task for the position C++ junior/middle developer. What i did wrong? Please help improve myself.
Task:
Description.
Write a template class - an array of any type of data, and tests to demonstrate the work with this class. Should be implemented all the methods also acceptable to extend the functionality.
Tests:
The solution should show a class with the following tests:
Working with numbers (int):
1.in loop insert 20 random numbers ranging from 0 to 100.
2.sorting the resulting set of numbers in ascending order.
3.remove each second element.
4.insert 10 random numbers ranging from 0 to 100 at random positions.
5.cleaning container.
After each stage you need to display the contents of the array onto the screen.
Working with objects (std: string):
1.in loop insert 15 randomly chosen words consisting of letters in lowercase.
2.sorting a set of words in ascending order.
3.removing each word comprising any of the letters a, b, c, d, e.
4.inserting 3 new randomly selected words on a random position.
After each stage you need to display the contents of the array onto the screen.
Class interface:
template <typename TData> class CArray { public: CArray(); CArray( const CArray & _array ); ~CArray(); void push_back( const TData & _value ); void insert( unsigned int _index, const TData & _value ); void erase( unsigned int _index ); void clear(); unsigned int size() const; TData & operator[](unsigned int _index ); };
Implementation:
#ifndef CARRAY_HPP__ # define CARRAY_HPP__ #include <stdexcept> #include <iterator> #include <ostream> #include <cstdlib> #include <ctime> namespace test { namespace util { ///********************** class RandGenerator { public: RandGenerator( unsigned int _upperbound = RAND_MAX ) : _mUpperbound(_upperbound) { std::srand( static_cast<unsigned int>(std::time(0)) ); } int operator()() { return std::rand() % _mUpperbound; } int operator()( unsigned int _upperbound ) { return std::rand() % _upperbound; } void set_seed( unsigned int _seed ) { std::srand( _seed ); } void set_upperbound( unsigned int _upperbound ) { _mUpperbound = _upperbound; } private: unsigned int _mUpperbound; }; ///********************** template <typename TClass> class _CArrayIter : public std::iterator<std::random_access_iterator_tag, TClass> { friend class CArray; public: explicit _CArrayIter( TClass * _ptype ) : _mTptr( _ptype ) {} const TClass & operator*() const { return *_mTptr; } TClass & operator*() { return *_mTptr; } const TClass * operator->() const { return _mTptr; } TClass * operator->() { return _mTptr; } _CArrayIter& operator++() { ++_mTptr; return *this; } _CArrayIter operator++( int ) { return _CArrayIter( _mTptr++ ); } _CArrayIter& operator--() { --_mTptr; return *this; } _CArrayIter operator--( int ) { return _CArrayIter( _mTptr-- ); } const _CArrayIter& operator[]( std::size_t _idx ) const { return _mTptr[ _idx ]; } _CArrayIter& operator[]( std::size_t _idx ) { return _mTptr[ _idx ]; } _CArrayIter& operator+=( std::size_t _val ) { _mTptr += _val; return *this; } _CArrayIter& operator-=( std::size_t _val ) { _mTptr -= _val; return *this; } _CArrayIter operator+( std::size_t _val ) { return _CArrayIter( _mTptr + _val ); } _CArrayIter operator-( std::size_t _val ) { return _CArrayIter( _mTptr - _val ); } friend bool operator==( const _CArrayIter & _lhs, const _CArrayIter & _rhs ) { return _lhs._mTptr == _rhs._mTptr; } friend bool operator!=( const _CArrayIter & _lhs, const _CArrayIter & _rhs ) { return _lhs._mTptr != _rhs._mTptr; } friend bool operator>( const _CArrayIter & _lhs, const _CArrayIter & _rhs ) { return _lhs._mTptr > _rhs._mTptr; } friend bool operator<( const _CArrayIter & _lhs, const _CArrayIter & _rhs ) { return _lhs._mTptr < _rhs._mTptr; } friend bool operator>=( const _CArrayIter & _lhs, const _CArrayIter & _rhs ) { return _lhs._mTptr >= _rhs._mTptr; } friend bool operator<=( const _CArrayIter & _lhs, const _CArrayIter & _rhs ) { return _lhs._mTptr <= _rhs._mTptr; } friend _CArrayIter operator+( std::size_t _st, const _CArrayIter & _iter ) { return _CArrayIter( _iter._mTptr + _st ); } friend std::size_t operator-( const _CArrayIter & _lhs, const _CArrayIter & _rhs ) { return _lhs._mTptr - _rhs._mTptr; } private: TClass *_mTptr; }; } ///********************** template <typename TData> class CArray { static const unsigned int CARRAY_DEFAULT_CAPACITY = 512; public: typedef test::util::_CArrayIter<TData> iterator; typedef test::util::_CArrayIter<const TData> const_iterator; CArray( unsigned int _capacity = CARRAY_DEFAULT_CAPACITY ): _mArray(static_cast<TData*>(::operator new[](_capacity * sizeof(TData)))), _mCurPos(0), _mEnd(_capacity) {} CArray( const CArray & _array ): _mArray(static_cast<TData*>(::operator new[](_array._mEnd * sizeof(TData)))), _mCurPos(_array._mCurPos), _mEnd(_array._mEnd) { _copy_n_init_from( _array._mArray, _array._mCurPos ); } ~CArray() { _destruct_objects(); ::operator delete[]( _mArray ); } void init_reserve( unsigned int _count ) { if( _count + _mCurPos >= _mEnd ) { _mEnd = _mCurPos + _count; _realloc_mem_copy(); } for( unsigned int end = _mCurPos + _count; _mCurPos < end; ++_mCurPos ) ::new(_mArray + _mCurPos) TData(); } void push_back( const TData & _value ) { if( _mCurPos == _mEnd ) _realloc_mem_copy(); ::new(_mArray + _mCurPos) TData( _value ); _mCurPos++; } void insert( unsigned int _index, const TData & _value ) { if( _index > _mCurPos ) _throw_out_of_range(); if( _index < _mCurPos ) { _move_mem_insert( _index ); ::new(_mArray + _index) TData( _value ); _mCurPos++; } else push_back( _value ); } void erase( unsigned int _index ) { if( _index >= _mCurPos ) _throw_out_of_range(); _move_mem_erase(_index); _mCurPos--; } void clear() { _destruct_objects(); _mCurPos = 0; } unsigned int size() const { return _mCurPos; } const TData & at( unsigned int _index ) const { if( _index >= _mCurPos ) _throw_out_of_range(); return _mArray[ _index ]; } TData & operator[]( unsigned int _index ) { return _mArray[ _index ]; } iterator begin() { return iterator(_mArray); } iterator end() { return iterator(_mArray + _mCurPos); } const_iterator cbegin() const { return const_iterator( _mArray ); } const_iterator cend() const { return const_iterator( _mArray + _mCurPos ); } friend std::ostream& operator<<( std::ostream & _outstream, const CArray & _obj ) { for( unsigned int i = 0; i < _obj._mCurPos; ++i ) _outstream << _obj._mArray[ i ] << "|"; return _outstream; } private: TData * _mArray; unsigned int _mCurPos, _mEnd; void _destruct_objects(); void _realloc_mem_copy(); void _move_mem_insert( unsigned int ); void _move_mem_erase( unsigned int ); void _copy_n_init_from( const TData*, unsigned int, unsigned int = 0, unsigned int = 0 ); CArray& operator=( const CArray& ) {} }; ///********************** template <typename TData> inline void CArray<TData>::_destruct_objects() { for( unsigned int i = 0; i < _mCurPos; ++i ) _mArray[ i ].TData::~TData(); } template <typename TData> void CArray<TData>::_realloc_mem_copy() { _mEnd *= 2; TData * tmp = static_cast<TData*>(::operator new[]( _mEnd * sizeof( TData ) )); for( unsigned int i = 0; i < _mCurPos; ++i ) { ::new(tmp + i) TData( _mArray[ i ] ); _mArray[ i ].TData::~TData(); } ::operator delete[]( _mArray ); _mArray = tmp; } template <typename TData> inline void CArray<TData>::_move_mem_insert( unsigned int _from ) { ::new(_mArray + _mCurPos) TData( _mArray[_mCurPos - 1] ); for( unsigned int i = _mCurPos - 1; i > _from; --i ) _mArray[ i ] = _mArray[ i - 1 ]; } template <typename TData> inline void CArray<TData>::_move_mem_erase( unsigned int _index ) { for( unsigned int i = _index; i < _mCurPos - 1; ++i ) _mArray[ i ] = _mArray[ i + 1 ]; _mArray[ _mCurPos - 1 ].TData::~TData(); } template <typename TData> inline void CArray<TData>::_copy_n_init_from( const TData *_src, unsigned int _length, unsigned int _srcPos, unsigned int _dstPos ) { for( unsigned int i = 0; i < _length; ++i ) ::new(_mArray + _dstPos++) TData( _src[ _srcPos++ ] ); } } #endif // !CARRAY_HPP__
And main.cpp:
#include <iostream> #include <algorithm> #include <string> #include "CArray.hpp" static const unsigned int MAX_WORD_LENGTH = 5; // = total length + min word length static const unsigned int MIN_WORD_LENGTH = 3; static inline bool _cmp( const std::string & s1, const std::string & s2 ) { return s1.size() < s2.size(); } template <typename Generator> static std::string _generate_word( Generator g ) { std::string str; for( unsigned int j = 0, end = g( MAX_WORD_LENGTH ) + MIN_WORD_LENGTH; j < end; ++j ) str.push_back( 'a' + g() ); return str; } int main() { test::CArray<int> c(20); test::util::RandGenerator gen( 100 ); c.init_reserve( 20 ); std::generate( c.begin(), c.end(), gen ); std::cout << "Test int1:\n" << c << std::endl; std::sort( c.begin(), c.end() ); std::cout << "\nTest int2:\n" << c << std::endl; for( unsigned int i = c.size() - 1; i > 0; --i ) if( (i & 1) != 0 ) c.erase( i ); std::cout << "\nTest int3:\n" << c << std::endl; for( unsigned int i = 0; i < 10; ++i ) c.insert( gen( c.size() ), gen() ); std::cout << "\nTest int4:\n" << c << std::endl; c.clear(); std::cout << "\nTest int5:\n" << c << std::endl; std::cout << "Integer testsuite done\n\n"; test::CArray<std::string> b; const std::string pattern( "abcde" ); gen.set_upperbound( 26 ); for( unsigned int i = 0; i < 15; ++i ) b.push_back( _generate_word(gen) ); std::cout << "\nTest str1:\n" << b << std::endl; std::sort( b.begin(), b.end(), _cmp ); std::cout << "\nTest str2:\n" << b << std::endl; for( unsigned int i = 0; i < b.size(); ++i ) if( b[ i ].find_first_of( pattern ) != std::string::npos ) b.erase( i-- ); std::cout << "\nTest str3:\n" << b << std::endl; for( unsigned int i = 0; i < 3; ++i ) b.insert(gen(b.size()), _generate_word(gen) ); std::cout << "\nTest str4:\n" << b << std::endl; std::cout << "\nString testsuite done\n" << std::endl; return 0; }
Working code and all tests pass.
CArray
class interface, or did you write it yourself?\$\endgroup\$