Making own collection class, exception driving me crazy!

I don't know why, but gives the following runtime error:
Exception thrown at 0x000D7D88 in ConsoleApplication19.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.

I understand, that somehow the "_trenutno"(number of elements) has the vrong value in it, but I don't understand how or why it occurs.
The debugger shows the next line to be executed is the return line at the int getTrenutno()const function.

The debugger also says that "this" object is initialized with wrong values.
this 0x00b3f59c {_trenutno=0xcccccccc {???} _elementi1=0xcccccccc {...} _elementi2=0xcccccccc {???} } Kolekcija<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,int> *

Additional info: commenting out the line in main where the fas object is initialized with the object returned from parovi.Duplikati() makes the code run smoothly - so the problem has something to do with that.

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <iostream>
#include <exception>
#include <string>
using namespace std;

class Greska:public exception {
	int _linija;
	char* _funkcija;
public:
	Greska(int l, char* f, char* poruka) :exception(poruka) {
		_linija = l;
		_funkcija = new char[strlen(f) + 1];
		strcpy_s(_funkcija, strlen(f) + 1, f);
	}
	void Info() {
		cout << "Greska na liniji: " << _linija << ", u funkciji: " << _funkcija << ", poruka: " << what() << endl;
	}
};


template <class T1, class T2>
class Kolekcija {
	int *_trenutno;
	T1 * _elementi1;
	T2 * _elementi2;
public:
	Kolekcija() {
		_trenutno = new int(0);
		_elementi1 = nullptr;
		_elementi2 = nullptr;
	}
	~Kolekcija() {
		delete[] _elementi1;
		delete[] _elementi2;
		_elementi1 = NULL;
		_elementi2 = NULL;
		delete _trenutno;
		_trenutno = NULL;
	}
	void AddElement(T1 e1, T2 e2) {
		int newSize = (*_trenutno)+1;
		T1 * temp1 = new T1[newSize];
		T2 * temp2 = new T2[newSize];
		if (newSize > 1) {
			for (int i = 0; i < *_trenutno; i++) {
				temp1[i] = _elementi1[i];
				temp2[i] = _elementi2[i];
			}
			temp1[*_trenutno] = e1;
			temp2[*_trenutno] = e2;
		}
		else {
			temp1[0] = e1;
			temp2[0] = e2;
		}
		delete[]_elementi1;
		delete[]_elementi2;
		_elementi1 = temp1;
		_elementi2 = temp2;
		(*_trenutno)++;
	}

	int getTrenutno()const {
		return (*_trenutno);
	}

	Kolekcija(Kolekcija<T1,T2>& obj) {
		_trenutno = new int(obj.getTrenutno());
		_elementi1 = new T1[obj.getTrenutno()];
		_elementi2 = new T2[obj.getTrenutno()];
		for (int i = 0; i < obj.getTrenutno(); i++) {
			_elementi1[i] = obj.getElement1(i);
			_elementi2[i] = obj.getElement2(i);
		}
	}
	Kolekcija& operator=(Kolekcija& druga) {
		if (this != druga) {
			delete _trenutno;
			delete[] _elementi1;
			delete[] _elementi2;
			_trenutno = new int(obj.getTrenutno());
			_elementi1 = new T1[obj.getTrenutno()];
			_elementi2 = new T2[obj.getTrenutno()];
			for (int i = 0; i < druga.getTrenutno(); i++) {
				_elementi1[i] = druga.getElement1(i);
				_elementi2[i] = druga.getElement2(i);
			}
		}
		return *this;
	}
	void Sortiraj() {
		bool gotov = false;
		while (!gotov) {
			gotov = true;
			for (int i = 0; i < (*_trenutno); i++) {
				for (int j = 0; j < (*_trenutno) - 1; j++) {
					if (_elementi1[j] > _elementi1[j + 1]) {
						gotov = false;
						T1 temp1 = _elementi1[j];
						T2 temp2 = _elementi2[j];
						_elementi1[j] = _elementi1[j + 1];
						_elementi2[j] = _elementi2[j + 1];
						_elementi1[j + 1] = temp1;
						_elementi2[j + 1] = temp2;
					}
				}
			}
		}
	}
	//function finds duplicates based on equal values between elements 1 and 2
        //example: _elementi1[0] = "A", _elementi2[0] = 2 is a duplicate if there is another       //index with the same values in _elementi1 and _elementi2
	Kolekcija& Duplikati() {
		int provjeravam = 0;
		Kolekcija<T1,T2> temp;
		for (int i = 0; i < (*_trenutno); i++) {
			provjeravam = i;
			for (int j = 0; j < (*_trenutno); j++) {
				if ((_elementi1[i] == _elementi1[j]) && (_elementi2[i] = _elementi2[j]) && provjeravam != j)
					temp.AddElement(_elementi1[i], _elementi2[i]);
			}
		}
		return temp;
	}
	T1 & const getElement1(int lokacija) {
		return _elementi1[lokacija];
	}
	T2 & const getElement2(int lokacija) {
		return _elementi2[lokacija];
	}
	friend ostream& operator <<<> (ostream&, Kolekcija<T1,T2>& );
};

template<class T1, class T2>
ostream& operator<<<> (ostream& COUT, Kolekcija<T1,T2>& obj) {
	for (int i = 0; i < obj.getTrenutno(); i++) {
		COUT << obj._elementi1[i] << ", " << obj._elementi2[i] << endl;
	}
	return COUT;
}



void main() {
	Kolekcija<int, int> a;
	for (int i = 0; i < 10; i++) {
		a.AddElement(i, i * 2);
	}
//	cout << a;
	int* b = new int(3);
	int newB = ++(*b);
	Kolekcija<string, int> parovi;
	parovi.AddElement("Mostar", 5);
	parovi.AddElement("Rajvosa", 159);
	parovi.AddElement("Gradacac", 92);
	parovi.AddElement("Banja Luka", 92);
	parovi.AddElement("Zenica", 1);
	parovi.AddElement("Banja Luka", 55);
	parovi.Sortiraj();
	cout << parovi;
	parovi.AddElement("Zenica", 1);
	parovi.AddElement("Rajvosa", 159);
    Kolekcija<string, int>fas = parovi.Duplikati();
	try {
		//nesto
	}
	catch (Greska& err) {
		err.Info();
	}
	system("pause>0");
}
Last edited on
This code will not compile. Compilable code that reproduces the issue may be helpful.
It compiles for me, I'm using visual studio 2015. What error do you get please? I don't know which part to leave out or how to make it less complex so that it actually compiles.
It compiles for me, I'm using visual studio 2015.

I'm using Visual Studio 2015. It doesn't compile for me and I guarantee if you cut and paste the code you've presented above it will not compile for you either.

On line 81 you are using the identifier obj which doesn't exist.

On line 124 you are trying to return a const reference (as opposed to a reference-to-const,) but const cannot be applied to a reference.
actually I did just that now and yesterday too when you said it won't compile! it compiles and gives the error I described above. let me try to change those.

This is the code:
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <iostream>
#include <exception>
#include <string>
using namespace std;

class Greska :public exception {
	int _linija;
	char* _funkcija;
public:
	Greska(int l, char* f, char* poruka) :exception(poruka) {
		_linija = l;
		_funkcija = new char[strlen(f) + 1];
		strcpy_s(_funkcija, strlen(f) + 1, f);
	}
	void Info() {
		cout << "Greska na liniji: " << _linija << ", u funkciji: " << _funkcija << ", poruka: " << what() << endl;
	}
};


template <class T1, class T2>
class Kolekcija {
	int *_trenutno;
	T1 * _elementi1;
	T2 * _elementi2;
public:
	Kolekcija() {
		_trenutno = new int(0);
		_elementi1 = nullptr;
		_elementi2 = nullptr;
	}
	~Kolekcija() {
		delete[] _elementi1;
		delete[] _elementi2;
		_elementi1 = NULL;
		_elementi2 = NULL;
		delete _trenutno;
		_trenutno = NULL;
	}
	void AddElement(T1 e1, T2 e2) {
		int newSize = (*_trenutno) + 1;
		T1 * temp1 = new T1[newSize];
		T2 * temp2 = new T2[newSize];
		if (newSize > 1) {
			for (int i = 0; i < *_trenutno; i++) {
				temp1[i] = _elementi1[i];
				temp2[i] = _elementi2[i];
			}
			temp1[*_trenutno] = e1;
			temp2[*_trenutno] = e2;
		}
		else {
			temp1[0] = e1;
			temp2[0] = e2;
		}
		delete[]_elementi1;
		delete[]_elementi2;
		_elementi1 = temp1;
		_elementi2 = temp2;
		(*_trenutno)++;
	}

	int getTrenutno() {
		return (*_trenutno);
	}

	Kolekcija(Kolekcija& obj) {
		_trenutno = new int(obj.getTrenutno());
		_elementi1 = new T1[obj.getTrenutno()];
		_elementi2 = new T2[obj.getTrenutno()];
		for (int i = 0; i < obj.getTrenutno(); i++) {
			_elementi1[i] = obj.getElement1(i);
			_elementi2[i] = obj.getElement2(i);
		}
	}

	Kolekcija& operator=(Kolekcija& druga) {
		if (this != druga) {
			delete _trenutno;
			delete[] _elementi1;
			delete[] _elementi2;
			_trenutno = new int(druga.getTrenutno());
			_elementi1 = new T1[druga.getTrenutno()];
			_elementi2 = new T2[druga.getTrenutno()];
			for (int i = 0; i < druga.getTrenutno(); i++) {
				_elementi1[i] = druga.getElement1(i);
				_elementi2[i] = druga.getElement2(i);
			}
		}
		return *this;
	}
	void Sortiraj() {
		bool gotov = false;
		while (!gotov) {
			gotov = true;
			for (int i = 0; i < (*_trenutno); i++) {
				for (int j = 0; j < (*_trenutno) - 1; j++) {
					if (_elementi1[j] > _elementi1[j + 1]) {
						gotov = false;
						T1 temp1 = _elementi1[j];
						T2 temp2 = _elementi2[j];
						_elementi1[j] = _elementi1[j + 1];
						_elementi2[j] = _elementi2[j + 1];
						_elementi1[j + 1] = temp1;
						_elementi2[j + 1] = temp2;
					}
				}
			}
		}
	}
	//function finds duplicates based on equal values between elements 1 and 2
	//example: _elementi1[0] = "A", _elementi2[0] = 2 is a duplicate if there is another       //index with the same values in _elementi1 and _elementi2
	Kolekcija& Duplikati() {
		int provjeravam = 0;
		Kolekcija<T1, T2> temp;
		for (int i = 0; i < (*_trenutno); i++) {
			provjeravam = i;
			for (int j = 0; j < (*_trenutno); j++) {
				if ((_elementi1[i] == _elementi1[j]) && (_elementi2[i] = _elementi2[j]) && provjeravam != j)
					temp.AddElement(_elementi1[i], _elementi2[i]);
			}
		}
		return temp;
	}
	T1& getElement1(int lokacija) {
		return _elementi1[lokacija];
	}
	T2& getElement2(int lokacija) {
		return _elementi2[lokacija];
	}
	friend ostream& operator <<<> (ostream&, Kolekcija<T1, T2>&);
};

template<class T1, class T2>
ostream& operator<<<> (ostream& COUT, Kolekcija<T1, T2>& obj) {
	for (int i = 0; i < obj.getTrenutno(); i++) {
		COUT << obj._elementi1[i] << ", " << obj._elementi2[i] << endl;
	}
	return COUT;
}



void main() {
	Kolekcija<int, int> a;
	for (int i = 0; i < 10; i++) {
		a.AddElement(i, i * 2);
	}
	//	cout << a;
	int* b = new int(3);
	int newB = ++(*b);
	Kolekcija<string, int> parovi;
	parovi.AddElement("Mostar", 5);
	parovi.AddElement("Rajvosa", 159);
	parovi.AddElement("Gradacac", 92);
	parovi.AddElement("Banja Luka", 92);
	parovi.AddElement("Zenica", 1);
	parovi.AddElement("Banja Luka", 55);
	parovi.Sortiraj();
	cout << parovi;
	parovi.AddElement("Zenica", 1);
	parovi.AddElement("Rajvosa", 159);
	Kolekcija<string, int>fas = parovi.Duplikati();
	try {
		//nesto
	}
	catch (Greska& err) {
		err.Info();
	}
	system("pause>0");
}


It gives the same error as before! Why, for Pete's sake...
Last edited on
using cpp.sh with all 3 warning options on:

In constructor 'Greska::Greska(int, char*, char*)':
10:56: error: no matching function for call to 'std::exception::exception(char*&)'
10:56: note: candidates are:
In file included from /usr/include/c++/4.9/ios:39:0, from /usr/include/c++/4.9/ostream:38, from /usr/include/c++/4.9/iostream:39, from 1: /usr/include/c++/4.9/exception:63:5:
note: std::exception::exception() exception() _GLIBCXX_USE_NOEXCEPT { } ^ /usr/include/c++/4.9/exception:63:5:
note: candidate expects 0 arguments, 1 provided /usr/include/c++/4.9/exception:60:9:
note: constexpr std::exception::exception(const std::exception&) class exception ^ /usr/include/c++/4.9/exception:60:9:
note: no known conversion for argument 1 from 'char*' to 'const std::exception&'
12:32: error: 'strlen' was not declared in this scope
13:39: error: 'strcpy_s' was not declared in this scope
At global scope:
124:37: error: 'const' qualifiers cannot be applied to 'T1&'
127:37: error: 'const' qualifiers cannot be applied to 'T2&'
In member function 'Kolekcija<T1, T2>& Kolekcija<T1, T2>::operator=(Kolekcija<T1, T2>&)':
81:24: error: 'obj' was not declared in this scope
At global scope:
134:60: error: template-id 'operator<< <>' in declaration of primary template
143:11: error: '::main' must return 'int' In instantiation of 'class Kolekcija<int, int>':
144:22: required from here
130:18: error: template-id 'operator<< <>' for 'std::ostream& operator<<(std::ostream&, Kolekcija<int, int>&)' does not match any template declaration In instantiation of 'class Kolekcija<std::basic_string<char>, int>':
151:25: required from here
130:18: error: template-id 'operator<< <>' for 'std::ostream& operator<<(std::ostream&, Kolekcija<std::basic_string<char>, int>&)' does not match any template declaration
In function 'int main()':
150:6: warning: unused variable 'newB' [-Wunused-variable]
In instantiation of 'std::ostream& operator<<(std::ostream&, Kolekcija<T1, T2>&) [with T1 = std::basic_string<char>; T2 = int; std::ostream = std::basic_ostream<char>]':
159:10: required from here 25:7: error: 'int* Kolekcija<std::basic_string<char>, int>::_elementi2' is private
136:54: error: within this context
24:7: error: 'std::basic_string<char>* Kolekcija<std::basic_string<char>, int>::_elementi1' is private
136:25: error: within this context In instantiation of 'Kolekcija<T1, T2>& Kolekcija<T1, T2>::Duplikati() [with T1 = std::basic_string<char>; T2 = int]':
162:50: required from here
114:20: warning: reference to local variable 'temp' returned [-Wreturn-local-addr]
is this something that is suppose to help a beginner out? I don't know how to make sense of all that

it looks like you've taken the code from the first post. I've made some adjustments, in the second post yet it spits out the same error...
Last edited on
Thank you everyone for trying to help me out!
I've managed to locate the error and it was in the Duplikati() function. I specified the return type as Kolekcija& instead of Kolekcija

if possible, I'd like someone to point out why that is a problem here.
Last edited on
actually I did just that now and yesterday too when you said it won't compile! it compiles and gives the error I described above.

I suspect that it didn't but you hit the "Yes, use the previously compiled version of this program" button that VS so "helpfully" offers up, because the code in the OP will not compile on any compiler.

I've managed to locate the error and it was in the Duplikati() function. I specified the return type as Kolekcija& instead of Kolekcija

if possible, I'd like someone to point out why that is a problem here.
Duplikati was returning a reference to a local object which stopped existing when Duplikati finished executing. The reference returned did not refer to a valid object.

"Dangling reference" if you're looking for search terms.
thanks for the explanation.

just for reference:
no, I noticed that prompt that sometimes pops up when you have a valid version that previously compiled as it explains and asks you to use the previously successful build(that is what it says), and it didn't pop up this time. the program compiled successfully with the code I pasted in the first post and then reached a runtime error that was described in the first post.

to be extra sure, I even made a completely new project, pasted the code from the first post and executed it - to the same result. compiles and makes a runtime error

it seems like you are experienced with cpp but this might be something new for you. if you're curious as to why this happened(which I am) we may look further into why and how it actually compiled.
Last edited on
if you're curious as to why this happened(which I am) we may look further into why and how it actually compiled.

Mystery solved. I had VS set up to use clang. Clang synthesizes the Kolekcija::operator= method which uses the invalid identifier. VC doesn't and fails to complain about your const reference syntax but does supply this very clear warning:
warning C4172: returning address of local variable or temporary: temp.

Not sure why clang synthesizes operator=. A cursory inspection doesn't reveal a need for it.
the program compiled successfully with the code I pasted in the first post and then reached a runtime error that was described in the first post.


Successful compilation depends on what options are passed to the compiler, and which compiler one uses. Note that the default compiler options might not be sufficient. Note that warnings are your friend, the more the compiler is able to report the better. As a coder, your job is not finished until you fix all of them. For example, using g++ I often see the appalling minimal:

g++ *.cpp

But something much better would be:

g++ -std=c++17 -Wall -Wextra -pedantic-errors *.cpp -o ExeFileName

I use these options as well, note they are not turned on by the seemingly comprehensive options above:
http://www.cplusplus.com/forum/general/183731/#msg899203

I also often see someone using VS, and their program compiles, but does not when other compilers with appropriate options are used. So that might symptomatic of how VS is setup - as cire mentions, his set up uses the clang compiler (which is very similar to g++ in terms of the options used).

So the best thing to do, is to compile your code with different compilers. If one compiler reports more warnings than another, then use that info to find out what the compiler option is to turn that warning on in the other compiler.
> Not sure why clang synthesizes operator=. A cursory inspection doesn't reveal a need for it.

clang++ does not instantiate the template, but it goes through phase one even if the template was never instantiated.

1
2
3
4
5
template < typename T > void foo(T) {  bad ; } // non-dependant name 'bad' looked up during phase one
                                               // always an error, no matter what T is

template < typename T > void bar(T) {  T::may_be_bad ; } // dependant name 'may_be_bad' looked up during phase two
                                                         // would be an error if instantiated with T == int 


clang++ would give an error for foo, even if the template is never instantiated.

Microsoft C++ does not parse the template at all before it is instantiated for the first time.
This in itself would be fine; the deal-breaker for Microsoft C++ is that it does not implement two-phase look up at all (not even in 2017RC; though they have promised to implement it by 'early 2017').
Topic archived. No new replies allowed.