Error: Unhandled exception etc

Hi,

I am trying to modify my function add() so it throws an exception every time an array passed already matches what is in the set. The code compiles but my visual studio keeps throwing an "unhandled exception" error and am at a lost point. Here is what we are mainly focusing on.

the function of focus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    template<class ItemType>
    void ArraySet<ItemType>::add(const ItemType& newEntry) {
        auto result1 = std::find(std::begin(items), std::end(items), newEntry);
        //int locatedIndex = getIndexOf(new);
        if (result1 == std::end(items))
       {
            throw DuplicateItemError();
       }    //Error
        else 
       {  
            items[itemCount] = newEntry;
            itemCount++;
       }  
    }  


Main file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <string>
#include "ArraySet.h"

using std::cout;
using std::endl;
using std::string;
using namespace cs_set;

void displaySet(ArraySet<string>& set) {
   cout << "The set contains " << set.getCurrentSize()
        << " items:" << endl;
   std::vector<string> setItems = set.toVector();
   
   int numEntries = setItems.size();
   for (int i = 0; i < numEntries; i++) {
      cout << setItems[i] << " ";
   }
   cout << endl << endl;
}




void setTester(ArraySet<string>& set)
{
    cout << "isEmpty: returns " << set.isEmpty()
         << "; should be 1 (true)" << endl;
    displaySet(set);

    std::string items[] = {"one", "two", "three", "four", "five", "one"};
    cout << "Add 6 items to the set: " << endl;
    for (int i = 0; i < 6; i++) {
        set.add(items[i]);
    }

    displaySet(set);
    
    cout << "isEmpty: returns " << set.isEmpty()
         << "; should be 0 (false)" << endl;

    cout << "getCurrentSize: returns " << set.getCurrentSize()
         << "; should be 6" << endl;

    try {
        cout << "Try to add another entry: add(\"extra\")... ";
        set.add("extra");
        cout << "should cause exception but didn't" << endl;
    } catch (ArraySet<string>::DuplicateItemError e) {
        cout << "should cause exception and did!" << endl;
    }
}





int main()
{
    ArraySet<string> set;
    cout << "Testing the Array-Based Set:" << endl;
    cout << "The initial set is empty." << endl;
    setTester(set);
    cout << "All done!" << endl;
}



Header file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#ifndef SET_INTERFACE
#define SET_INTERFACE

#include <vector>
#include <algorithm>
#include <iterator>

namespace cs_set {
    template<class ItemType>
    class SetInterface
    {
    public:
       /** Gets the current number of entries in this bag.
        @return  The integer number of entries currently in the bag. */
       virtual int getCurrentSize() const = 0;
   
       /** Sees whether this bag is empty.
        @return  True if the bag is empty, or false if not. */
       virtual bool isEmpty() const = 0;
   
       /** Adds a new entry to this bag.
        @post  If successful, newEntry is stored in the bag and
           the count of items in the bag has increased by 1.
        @param newEntry  The object to be added as a new entry.
        @return  True if addition was successful, or false if not. */
       virtual void add(const ItemType& newEntry) = 0;
   
       /** Removes one occurrence of a given entry from this bag,
           if possible.
        @post  If successful, anEntry has been removed from the bag
           and the count of items in the bag has decreased by 1.
        @param anEntry  The entry to be removed.
        @return  True if removal was successful, or false if not. */
       virtual void remove(const ItemType& anEntry) = 0;
   
       /** Removes all entries from this bag.
        @post  Bag contains no items, and the count of items is 0. */
       virtual void clear() = 0;
   
       /** Counts the number of times a given entry appears in this bag.
        @param anEntry  The entry to be counted.
        @return  The number of times anEntry appears in the bag. */
      // virtual int getFrequencyOf(const ItemType& anEntry) const = 0;
   
       /** Tests whether this bag contains a given entry.
        @param anEntry  The entry to locate.
        @return  True if bag contains anEntry, or false otherwise. */
       virtual bool contains(const ItemType& anEntry) const = 0;
   
       /** Empties and then fills a given vector with all entries that
           are in this bag.
        @return  A vector containing all the entries in the bag. */
       virtual std::vector<ItemType> toVector() const = 0;
   
       /** Destroys this bag and frees its assigned memory. (See C++ Interlude 2.) */
       virtual ~SetInterface() { }
    };
}
#endif 


cpp file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

namespace cs_set {

    template<class ItemType>
    void ArraySet<ItemType>::add(const ItemType& newEntry) {
        auto result1 = std::find(std::begin(items), std::end(items), newEntry);
        //int locatedIndex = getIndexOf(new);
        if (result1 == std::end(items))
       {
            throw DuplicateItemError();
       }    //Error
        else 
       {  
            items[itemCount] = newEntry;
            itemCount++;
       }  
    }  




    template<class ItemType>
    ArraySet<ItemType>::ArraySet() {
        itemCount = 0;
        maxItems = DEFAULT_CAPACITY;
    }





    template<class ItemType>
    int ArraySet<ItemType>::getCurrentSize() const {
        return itemCount;
    }





    template<class ItemType>
    bool ArraySet<ItemType>::isEmpty() const {
        return itemCount == 0;
    }




    template<class ItemType>
    std::vector<ItemType> ArraySet<ItemType>::toVector() const {
        std::vector<ItemType> setContents;
        for (int i = 0; i < itemCount; i++) {
            setContents.push_back(items[i]);
        }
      
        return setContents;
    }




    template <class ItemType>
    bool ArraySet<ItemType>::contains(const ItemType& anEntry) const {
        bool isFound = false;
        int curIndex = 0;
        while (!isFound && (curIndex < itemCount)) {
            isFound = (anEntry == items[curIndex]);
            if (!isFound) {
                curIndex++;
            }
        }

        return isFound;
    }
    
    




    template<class ItemType>
    void ArraySet<ItemType>::clear() {
        itemCount = 0;
    }





    template<class ItemType>
    int ArraySet<ItemType>::getIndexOf(const ItemType& target) const {
        bool isFound = false;
        int result = -1;
        int searchIndex = 0;

        while (!isFound && (searchIndex < itemCount)) {
            isFound = (items[searchIndex] == target);
            if (isFound) {
                result = searchIndex;
            } else {
                searchIndex++;
            }
        }

        return result;
    }






    template<class ItemType>
    void ArraySet<ItemType>::remove(const ItemType& anEntry) {
        int locatedIndex = getIndexOf(anEntry);
        if (locatedIndex > -1) {
            itemCount--;
            items[locatedIndex] = items[itemCount];
        } else {
            throw ItemNotFoundError();
        }
    }
}


Secondary Header file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef ARRAY_SET_
#define ARRAY_SET_
#include <algorithm>
#include <iterator>
#include "SetInterface.h"

namespace cs_set {
    template<class ItemType>
    class ArraySet : public SetInterface<ItemType>
    {
        public:
            typedef ItemType value_type;
        
            class DuplicateItemError {};
            class ItemNotFoundError {};
        
            ArraySet();
            int getCurrentSize() const;
            bool isEmpty() const;
            void add(const ItemType& newEntry);
            void remove(const ItemType& anEntry);
            void clear();
            bool contains(const ItemType& anEntry) const;
            //int getFrequencyOf(const ItemType& anEntry) const;
            std::vector<ItemType> toVector() const;
        private:
            static const int DEFAULT_CAPACITY = 6;
            ItemType items[DEFAULT_CAPACITY];
            int itemCount;
            int maxItems;
   
            // Returns either the index of the element in the array items that
            // contains the given target or -1, if the array does not contain 
            // the target.
            int getIndexOf(const ItemType& target) const;   
    };
}

#include "ArraySet.cpp"
#endif 
Last edited on
Change the name of ArraySet.cpp to some other extension. I like ".tcpp" ,myself.

A .cpp is intended to be compiled. Your ArraySet.cpp is template code that cannot be compiled until it is instantiated. I like how you include this file from your ArraySet.h file, but do yourself a favor and don't use .cpp as an extension.

p.s. I don't know if that will fix your problem, but it's a start.
@doug4 i excluded that file from my visual studio so it would compile but the problem is in the add() function itself it keeps throwing an unhandled exception error like this one,

1
2
3
4
5
Unhandled exception at 0x74E440B2 in ArraySetV1.exe: Microsoft C++ exception: 

cs_set::ArraySetstd::basic_string<char,std::char_traits<char,std::allocator > 

>::DuplicateItemError at memory location 0x00AFF577.


Any guidance on fixing the function so it can throw the exception like it is supposed to would be appreciated.
Last edited on
You didn't put your calls to add inside a try/catch block in line 33. The attempt to add the last string is a duplicate of the first string, so the add function throws the exception. Because there's no try/catch, the exception is unhandled.

Edit: BTW, line 47 will not cause an exception as you expect because you never check to see if adding the item in line 14 of ArraySet.cpp is out of bounds.
Last edited on
I am a bit lost on the first statement of adding try/catch blocks in line 33, which file where you mentioning?
Sorry. Line 34 in the main file.

The loop from line 33 - line 35 calls add 6 times, the last time causing the DuplicateItemError to be thrown.
Oh okay, i understand that now it iterates through and sees that the last time it is called it is a pre existing string. Would I need to add another try/catch in the loop to prevent getting a unhandled exception error?
Last edited on
@doug4

Updated code in main void setTester:

1
2
3
4
5
6
7
8
9
10
11
12
13
    std::string items[] = {"one", "two", "three", "four", "five", "one"};
    cout << "Add 6 items to the set: " << endl;
    for (int i = 0; i < 6; i++) {
        
        try {
            set.add(items[i]);
            cout << "Exception?" << endl;
        }
        catch (ArraySet<string>::DuplicateItemError e)
        {
            cout << "EXCEPTION!" << endl;
        }
    }


The output is

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Testing the Array-Based Set:
The initial set is empty.
isEmpty: returns 1; should be 1 (true)
The set contains 0 items:


Add 6 items to the set:
EXCEPTION!
EXCEPTION!
EXCEPTION!
EXCEPTION!
EXCEPTION!
EXCEPTION!
The set contains 0 items:


isEmpty: returns 1; should be 0 (false)
getCurrentSize: returns 0; should be 6
All done!


The try/catch apparently outputs that every element in the array is a duplicate??????

Even though the only ones that should be a duplicate should be the first element and the last...
Last edited on
You need to learn to debug stuff on your own. That's what programming is all about.

I assumed your check for a duplicate was correct and didn't really look at it too carefully. On closer look, there is an error.

Why don't you debug your add function and see why it keeps throwing an error. Asking me to debug your code for you will stunt your programming growth.
@doug4

WOOOOO, You are right! Going back and debugging and implementing new methods to solve the problems will help me grow. I got it to work correctly.

the output is now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Testing the Array-Based Set:
The initial set is empty.
isEmpty: returns 1; should be 1 (true)
The set contains 0 items:


Add 6 items to the set:
one
two
three
four
five
IT IS A DUPLICATE!
The set contains 5 items:
one two three four five

isEmpty: returns 0; should be 0 (false)
getCurrentSize: returns 5; should be 6
All done!

To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .


I did not change anything in void setTester but instead in the add() function of the class I changed from using the auto result1 to this instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    template<class ItemType>
    void ArraySet<ItemType>::add(const ItemType& newEntry) {
        //auto result1 = std::find(std::begin(items), std::end(items), newEntry);
        //int locatedIndex = getIndexOf(new);
        if (std::find(std::begin(items), std::end(items), newEntry) != std::end(items))
       {
            throw DuplicateItemError();
       }  
        else 
       {  
            items[itemCount] = newEntry;
            itemCount++;
       }  
    }  
Last edited on
Way to go! It feels good to fix a bug in your code, doesn't it?

Something you might be interested in: When printing out Boolean values, if you want to see "true" or "false", you can use the std::boolalpha stream manipulator found in <iomanip>. Call it once on a stream, and all prints (actually stream insertions) of bools onto that stream will show up as the text values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <iomanip>

int main()
{
    bool a = true;
    bool b = false;

    std::cout << "Before boolalpha" << std::endl;
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << std::boolalpha;

    std::cout << "After boolalpha" << std::endl;
    std::cout << a << std::endl;
    std::cout << b << std::endl;
}
Last edited on
Shouldn't add() be using contains() (or .getIndexOf() )?

1
2
3
4
5
6
7
template<class ItemType>
    void ArraySet<ItemType>::add(const ItemType& newEntry) {
        if (contains(newEntry))
            throw DuplicateItemError();
        else
            items[itemCount++] = newEntry;
    }


Shouldn't contains() use getIndexOf() ?

1
2
3
4
template <class ItemType>
    inline bool ArraySet<ItemType>::contains(const ItemType& anEntry) const {
        return getIndexOf(anEntry) >= 0;
    }


and getIndexof() can be simplified somewhat:

1
2
3
4
5
6
7
template<class ItemType>
    int ArraySet<ItemType>::getIndexOf(const ItemType& target) const {
        const auto itend = std::begin(items) + itemCount;
        const auto indx = std::find(std::begin(items), itend, target);

        return indx == itend ? -1 : std::distance(std::begin(items), itend) ;
    }



Also note that if you're using C++17, then constructs like:

1
2
3
4
5
6
7
8
9
10
 template<class ItemType>
    void ArraySet<ItemType>::remove(const ItemType& anEntry) {
        int locatedIndex = getIndexOf(anEntry);
        if (locatedIndex > -1) {
            itemCount--;
            items[locatedIndex] = items[itemCount];
        } else {
            throw ItemNotFoundError();
        }
    }


can be 'simplied' as:

1
2
3
4
5
6
7
 template<class ItemType>
    void ArraySet<ItemType>::remove(const ItemType& anEntry) {
        if (const int locatedIndex = getIndexOf(anEntry); locatedIndex > -1)
            items[locatedIndex] = items[--itemCount];
        else
            throw ItemNotFoundError();
    }

Topic archived. No new replies allowed.