Click here to Skip to main content
16,019,876 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
1. Why does vs 2020 not recognise Array<t>::iterator in the program bellow/
2. Why does the operator[] (size_t Index) Keep throwing an exception when Index = 0. there is obviouly nothing wrong with the logic. Is this a vs2020 bug?


C++
<pre>#pragma once
#include <stdexcept>
using namespace std;
template <typename T>
class Array;

template <typename T>
void swap(Array<T>& obj1, Array<T>& obj2) noexcept;

template <typename T>
class Array
{
	size_t m_iSize{ 1000 };
	size_t m_iCount = 0;
	T *m_pData = nullptr;
public:

	class iterator;

	Array() = default;
	explicit Array(size_t iSize);
	Array(const Array& Obj);
	Array &operator=(const Array& Obj);
	Array(Array&& obj) noexcept;
	Array &operator=(Array&& obj) noexcept;
	Array operator+ (const Array &obj);
	Array operator- (const Array &obj);
	Array operator+= (const Array &obj);
	Array operator-= (const Array &obj);
	T& operator[](size_t Index);
	const T& operator[](size_t Index) const;
	void Add(const T& Data);
	void Add(T&& Data);
	size_t GetSize() const noexcept { return m_iCount; }
	void swap(Array &obj) noexcept;
	friend void swap(Array& obj1, Array& obj2);
	~Array() { delete m_pData; }

	iterator erase(iterator p);
	iterator erase(iterator pStart, iterator pStop);
	iterator begin();
	iterator end();
};

template<typename T>
class Array<T>::iterator
{
	size_t m_iCurrent;
	explicit iterator(size_t iCount);
public:
	iterator();
	iterator(const iterator& obj);
	iterator operator=(const iterator& obj);
	bool operator==(const iterator& obj);
	bool operator!= (const iterator& obj);
	iterator operator+ (const iterator& obj);
	iterator operator- (const iterator& obj);
	bool operator< (const iterator& obj);
	bool operator> (const iterator& obj);
	T& operator[](size_t Index);
	const T& operator[](size_t Index) const;
	T operator *();
	iterator operator +(size_t Index);
	iterator operator -(size_t Index);

};



template<typename T>
Array<T>::iterator::iterator()//visual studio does not  Array<T>::iterator::
{
	m_iCurrent = -1;
}

template<typename T>
Array<T>::iterator::iterator(size_t iCount)
{
	m_iCount = iCount;
}

template<typename T>
Array<T>::iterator::iterator(const iterator& obj):m_iCount{obj.m_iCount}
{
	
}

template<typename T>
Array<T>::iterator Array<T>::iterator::operator= (const iterator& obj)
{
	m_iCount = obj.m_iCount;

	return *this;
}

template<typename T>
bool Array<T>::iterator::operator==(const iterator& obj)
{
	return (m_iCount == obj.m_iCount);
}

template<typename T>
bool Array<T>::iterator::operator!= (const iterator& obj)
{
	return !(*this == obj);
}

template<typename T>
Array<T>::iterator Array<T>::iterator::operator+ (const iterator& obj)
{
	return Array<T>::iterator{m_iCount + obj.m_iCount};
}

template<typename T> 
Array<T>::iterator Array<T>::iterator::operator- (const iterator& obj)
{
	return Array<T>::iterator{m_iCount - obj.m_iCount};
}

template<typename T>
bool Array<T>::iterator::operator< (const iterator& obj)
{
	return (m_iCount < obj.m_iCount);
}

template<typename T>
bool Array<T>::iterator:: operator> (const iterator& obj)
{
	return !((*this == obj) || (*this < obj));
}

template<typename T>
T& Array<T>::iterator::operator[](size_t Index)
{ 
	if (Index <= -1 || Index >= m_iCount) throw std::range_error("Invalid Index");//This line keep throwing an exception when 
index = 0;
	return m_pData[Index]; 
}

template<typename T>
const T& Array<T>::iterator::operator[](size_t Index) const 
{
	if (Index <= -1 || Index >= m_iCount) throw std::range_error("Invalid Index");
	return m_pData[Index];
}

template<typename T>
T Array<T>::iterator::operator *()
{
	if (m_iCurrent <= -1) throw std::runtime_error("Iterator has not been initialized");
	if (m_iCurrent => m_iCount) throw std::runtime_error("Invalid Array location");
	
	return m_pData[m_iCurrent];
}

template<typename T>
Array<T>::iterator Array<T>::iterator::operator +(size_t Index)
{
	m_iCurrent += Index;

	return *this;
}

template<typename T>
Array<T>::iterator Array<T>::iterator::operator -(size_t Index)
{
	m_iCurrent -= Index;

	return *this;
}

template<typename T>
Array<T>::iterator Array<T>::begin()
{
	Array<T>::iterator p{0};
	
	return p;
}

template<typename T>
Array<T>::iterator Array<T>::end()
{
	Array<T>::iterator p{m_iCount};
	
	return p;
}

template <typename T>
Array<T>::iterator Array<T>::erase(Array<T>::iterator p)
{
	if ((m_iCount - p.m_iCount) <= 0) throw std::range_error{"Ivalid Array location"};
	
	m_iCount -= p.m_iCount;

	Array<T>::iterator p{m_iCount};
	
	return *this;
}

template <typename T>
Array<T>::iterator Array<T>::erase(iterator pStart, iterator pStop)
{
	if ((m_iCount - (pStop.m_iCount - pStart.m_iCount)) <= 0) throw std::range_error{"Invalid Array location"};
	
	m_iCount -= (pStop.m_iCount - pStart.m_iCount);

	Array<T>::iterator p{m_iCount};

	return *this;
}



template <typename T>
void swap(Array<T>& obj1, Array<T>& obj2) noexcept
{
	obj1.swap(obj2);
}

template <typename T>
void Array<T>::swap(Array &obj) noexcept
{
	std::swap(m_iSize, obj.m_iSize);
	std::swap(m_pData, obj.m_pData);
	std::swap(m_iCount, obj.m_iCount);
}

 template <typename T>
 Array<T>::Array(size_t iSize):m_iSize{iSize}
{
	 m_pData = new T [m_iSize];
}

 template <typename T>
 Array<T>::Array(const Array& obj):m_iSize(obj.m_iSize),m_iCount{obj.m_iCount}
 {
	 m_pData = new T[m_iSize];
	 for(size_t i = 0; i < m_iCount; ++i)
	 {
		 m_pData[i] = obj.m_pData[i];
	 }
 }

 template <typename T>
 Array<T>& Array<T>::operator=(const Array& Obj)
 { 
	 Array<T> Copy{Obj};
	 swap(Copy);

	 return *this;
 }

 template<typename T>
 Array<T>::Array(Array&& obj) noexcept :m_iSize{obj.m_iSize},m_iCount{obj.m_iCount},m_pData{obj.m_pData}
 {
	 obj.m_pData = nullptr;
 }

 template <typename T>
 Array<T>& Array<T>::operator=(Array&& obj) noexcept
 {
	 Array<T> Copy{ std::move(obj) };
	 swap(Copy);

	 return *this;
 }

 template<typename T>
 Array<T> Array<T>::operator+ (const Array& obj)
 {	 
	 Array<T> Temp{*this};
	 if ((Temp.m_iCount + obj.m_iCount) > Temp.m_iSize)
	 {
		 Temp = Array<T>{ (Temp.m_iCount + obj.m_iCount) + 1000 };
		 Temp.m_iCount = m_iCount;
	 }
	 
	 size_t iTemp = Temp.m_iCount;
	 Temp.m_iCount += obj.m_iCount;
	 for (size_t i = iTemp; i < Temp.m_iCount; ++i)
	 {
		 Temp.m_pData[i] = obj.m_pData[i - iTemp];
	 }

	 return Temp;
 }

 template<typename T>
 Array<T> Array<T>::operator- (const Array& obj)
 {
	 Array<T> Temp{ *this };
	 for (size_t i = 0; i < obj.m_iCount; ++i)
	 {
		 Array<T>::iterator p = std::find(begin(), end(), obj.m_pData[i]);
		 p = std::remove(begin(), end(), *p)
		 size_t iCount = std::distance(p, end());
		 erase(p,end());
		 
		 Temp.m_iCount -= iCount;
	 }

	 return Temp;
 }

 template<typename T>
 Array<T> Array<T>::operator+= (const Array& obj)
 {
	 Array<T> Temp = *this + obj;

	 swap(Temp);
	   
	 return *this;
 }

 template<typename T>
 Array<T> Array<T>::operator-= (const Array& obj)
 {
	 Array<T> Temp = *this - obj;

	 swap(Temp);

	 return * this;
 }

 template<typename T>
 T& Array<T>::operator[](size_t Index) 
 {
	 if (Index <= -1 || Index >= m_iCount) throw std::out_of_range("Invalid Index");

	 return m_pData[Index];
 }
 template<typename T>
 const T& Array<T>::operator[](size_t Index) const
 {
	 if (Index <= -1 || Index >= m_iCount) throw std::out_of_range("Invalid Index");

	 return m_pData[Index];
 }

 template<typename T>
void Array<T>::Add(const T& Data)
{
	if (m_iCount < m_iSize)
	{
		m_pData[m_iCount] = Data;
		m_iCount++;
	}
	else
	{
		Array<T> Temp{ m_iSize + 1000};
		Temp.m_iCount = m_iCount;
		for (size_t i = 0; i < Temp.m_iCount; i++)
		{
			Temp[i] = m_pData[i];
		}
		Temp[m_iCount] = Data;
		Temp.m_iCount++;
		swap(Temp);
	}
}

template<typename T>
void Array<T>::Add(T&& Data)
{
	if (m_iCount < m_iSize)
	{
		m_pData[m_iCount] = Data;
		m_iCount++;
	}
	else
	{
		Array<T> Temp{ m_iSize + 1000};
		Temp.m_iCount = m_iCount;
		for (size_t i = 0; i < Temp.m_iCount; i++)
		{
			Temp[i] = std::move(m_pData[i]);
		}
		Temp[m_iCount] = std::move(Data);
		Temp.m_iCount++;
		swap(Temp);
	}
}



<pre>#include "Array.h"
#include <iostream>

int main()
{
	try
	{
		Array<int> aArray{ 100 };
		for (size_t i{}; i < 10; ++i) aArray.Add(static_cast<int>(i));

		std::cout << "The data in the array are:";
		for (size_t i{}; i < 10; i++) std::cout << aArray[i] << ' ';
		cout << endl;

		Array<int> aArray1 { aArray};
		std::cout << "The data in the array1 are:";
		for (size_t i{}; i < 10; ++i) std::cout << aArray1[i] << ' ';
		cout << endl;

		Array<int> aArray2 {aArray + aArray1};
		std::cout << "The data in the array2 are:";
		for (size_t i{}; i < aArray2.GetSize(); i++) std::cout << aArray2[i] << ' ';
		cout << endl;

		Array<int> aArray3;
		aArray3 = aArray2;
		std::cout << "The data in the array3 are:";
		for (size_t i{}; i < aArray3.GetSize(); ++i) std::cout << aArray3[i] << ' ';
		cout << endl;

		Array<int> aArray4;
		aArray4 = aArray3 + aArray2;
		std::cout << "The data in the array4 are:";
		for (size_t i{}; i < aArray4.GetSize(); i++) std::cout << aArray4[i] << ' ';
		cout << std::endl;

		Array<int> aArray5;
		aArray5 += aArray4;
		std::cout << "The data in the array5 are:";
		for (size_t i{}; i < aArray5.GetSize(); ++i) std::cout << aArray5[i] << ' ';
		cout << endl;


		//Array<int> aArray6;
		//aArray6 -= aArray;
		//std::cout << "The data in the array5 are:";
		//for (size_t i{}; i < aArray6.GetSize(); i++) std::cout << aArray6[i] << ' ' << std::endl;
	}
	catch (std::out_of_range& error)
	{
		cout << error.what() << endl;
	}
	
	return 0;
}




What I have tried:

I have spent hours debugging and I am not sure google can help with this.
Posted
Updated 5-Aug-23 7:31am
v3
Comments
Richard MacCutchan 5-Aug-23 6:47am    
You need to show the actual implementation code you are using, and indicate where the error message occurs. I also noticed that in your overloads of plus and minus, you refer to m_Count, but in the template you declare m_iCount.
Gbenbam 5-Aug-23 7:27am    
The problem is that the program did not even compile. the first error is "Error C2061 syntax error: identifier 'iterator'". There are other errors they are so many and I believe they are all caused by the initial error stated above. If the initial error is corrected all of the remaining error messages will probably not show up again. So, I commented out every thing that had to do with the iterator class, the program then compiled but on running it, it kept throwing exceptions without any logical reason.
Richard MacCutchan 5-Aug-23 7:33am    
There is always a logical reason for exceptions. You just need to use the debugger to find them.
Gbenbam 5-Aug-23 7:40am    
The condition that I set for throwing an exception is: if (Index <= -1 || Index >= m_iCount).
As revealed from debugging, the exception was thrown when Index = 0. You use zero to replace Index in the conditional statement and see if the result will satisfy the condition for throwing exeption.
Richard MacCutchan 5-Aug-23 8:06am    
Fine, but you need to trap the code at that point and examine all data to see why it is throwing the exception. The issue is specific to the data that you are processing so no one else can recreate the problem for you.

1 solution

This was very, very weird. I spent quite a bit of time debugging and I could not find the problem either. In the end, I side-stepped it and got something to work. I did that by adding this method :
C++
bool IsValid( size_t index ) { return ( index < m_iCount ); }
and then I adjusted two operators to look like this :
C++
template< typename T >
T& Array< T >::operator[]( size_t index ) 
{
    if( ! IsValid( index ) )
        throw std::out_of_range("Invalid Index");

    return m_pData[ index ];
}

template< typename T >
const T& Array< T >::operator[]( size_t index ) const
{
    if( ! IsValid( index ) )
        throw std::out_of_range("Invalid Index");

    return m_pData[ index ];
}
and this works as expected - no exceptions are thrown.

I had to hack the code a bit to make it compile with VisualStudio 2022. It complained about the iterator class and its implementation. I folded all of that into the Array class and made it all inline and then things compiled and ran. However, there is still a problem with the -= operator's implementation so the test code you have commented out will not compile. I didn't figure that out. I see that it uses std::remove and distance so that probably needs to be revisted. Anyway, here are what my revisions look like :
C++
template< typename T >
class Array
{
    size_t  m_iSize     = 1000;
    size_t  m_iCount    = 0;
    T *     m_pData     = nullptr;

public:
    Array() = default;
    explicit Array( size_t iSize );
    Array( const Array & Obj );
    Array( Array && obj ) noexcept;
    ~Array()                                { delete m_pData; }

    Array & operator = ( const Array& Obj );
    Array & operator = ( Array&& obj ) noexcept;
    Array   operator + ( const Array &obj );
    Array   operator - ( const Array &obj );
    Array   operator += ( const Array &obj );
    Array   operator -= ( const Array &obj );
    T &     operator[]( size_t Index );
    const T& operator[]( size_t Index ) const;

    void    Add( const T& Data );
    void    Add( T && Data );
    size_t  GetSize() const noexcept        { return m_iCount; }
    void    swap( Array &obj ) noexcept;
    friend void swap( Array& obj1, Array& obj2 );

    bool    IsValid( size_t index )         { return ( index < m_iCount ); }

    template< typename T >
    class iterator
    {
        size_t m_iCurrent;
        explicit iterator( size_t iCount )              { m_iCount = iCount; }

    public:
        iterator()                                      { m_iCurrent = -1; }
        iterator( const iterator & obj ) : m_iCount( obj.m_iCount ) {}

        iterator operator = ( const iterator& obj ) { m_iCount = obj.m_iCount; return *this; }
        bool operator == ( const iterator& obj )    { return ( m_iCount == obj.m_iCount ); }
        bool operator != ( const iterator& obj )    { return ! ( *this == obj ); }

        iterator operator + ( const iterator& obj ) { return Array< T >::iterator{ m_iCount + obj.m_iCount }; }
        iterator operator - (const iterator& obj)   { return Array< T >::iterator{ m_iCount - obj.m_iCount }; }

        iterator operator + ( size_t Index )            { m_iCurrent += Index; return *this; }
        iterator operator - ( size_t Index )            { m_iCurrent -= Index; return *this; }

        bool operator < ( const iterator& obj )  { return ( m_iCount < obj.m_iCount ); }
        bool operator > ( const iterator& obj )  { return ! ( ( *this == obj ) || ( *this < obj ) ); }

        T & operator[]( size_t Index )
        { 
            if( Index >= m_iCount )
                throw std::range_error("Invalid Index");    //This line keep throwing an exception when index = 0;
            return m_pData[ Index ];
        }

        const T& operator[]( size_t Index ) const
        {
            if( Index >= m_iCount )
                throw std::range_error( "Invalid Index" );
            return m_pData[ Index ];
        }

        T operator *()
        {
//          if( m_iCurrent <= -1 ) throw std::runtime_error( "Iterator has not been initialized" );
            if( m_iCurrent => m_iCount ) throw std::runtime_error( "Invalid Array location" );
            return m_pData[ m_iCurrent ];
        }
    };

    iterator< T > erase( iterator< T > p )
    {
        if( ( m_iCount - p.m_iCount ) <= 0 )
            throw std::range_error{ "Ivalid Array location" };
    
        m_iCount -= p.m_iCount;
        Array< T >::iterator p{ m_iCount };
        return *this;
    }

    iterator< T > erase( iterator< T > pStart, iterator< T > pStop )
    {
        if( ( m_iCount - ( pStop.m_iCount - pStart.m_iCount ) ) <= 0 )
            throw std::range_error{ "Invalid Array location" };
    
        m_iCount -= ( pStop.m_iCount - pStart.m_iCount );
        Array< T >::iterator p{ m_iCount };
        return *this;
    }

    iterator< T > begin()   { Array<T>::iterator p{ 0 }; return p; }
    iterator< T > end()     { Array<T>::iterator p{ m_iCount }; return p; }
};
 
Share this answer
 
v3
Comments
Rick York 5-Aug-23 13:36pm    
One thing I still find odd about this : I did not have a problem with the [] operators in the iterator class so they do not call the IsValid method.
Rick York 5-Aug-23 13:41pm    
I suspect the issue has to do with the <=-1 comparison with an unsigned value. I haven't looked at the assembly code generated to verify though. Regardless, I think this is a compiler bug.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900