Debugging a program, could use assistance

Definitely still need help, because this is mad confusing!

I've mostly zeroed in on the problem since I've written it down in this thread. The details are now in the post below this one, with just related code and some segments of my search in this post. Thanks for taking a peek into here!


So I turned on the debugger in VC++2k8 and got this message with a little arrow next to it:
 
>	robo2.exe!std::_Vector_const_iterator<int,std::allocator<int> >::operator+=(int _Off = 1) Line 163	C++


It references this call:
1
2
3
4
5
case 1:
//cout << "case1 called" << endl;
robopoint->at(i).robogather(probocounter);
//cout << "if this doesn't show, case1 is broken" << endl;
break;


Which calls this interface function:
1
2
3
4
5
6
7

void Robot::robogather(Robocensus * probocounter) {
	if (food.get_food_hoard() ==-1)
		isdead =1;
	else
		food.gather(probocounter, isoptimist);
}


Which calls this actual function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*Relevant Definitions:
int food_hoard, efficiency;
std::vector<int> history_gather;
*/

void Food::gather(Robocensus * robocen, bool isoptimist) {
	
	int poptot = robocen->get_pop('l');
	int gathered_food = (const_carrying_capacity + efficiency)/poptot;
	history_gather.push_back(gathered_food);
	food_hoard += gathered_food;
	get_history_reg(isoptimist); //UPDATE: This is the call that causes problems, more code
//follows in the next post.

}




Last edited on
Ok, so I used commenting to chase it down and I was wrong, it's definitely the regression element that's causing the problem because commenting it out prevents the exception from being thrown. Must not have tested it as thoroughly as I thought! I guess the next step is figuring out where in here the problem is coming from.

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
void Food::get_history_reg(bool isoptimist){
	//http://en.wikipedia.org/wiki/Simple_linear_regression#Numerical_example
	//quick brush up on regression w/ example

	const int historysize = history_gather.size(); //reinforces that vector should not change size

	get_avg_gather(isoptimist);

	//create time
	std::vector<int> time; 
	for (int i=0; i<historysize; i++)
		time.push_back(i);

	const int timesize = time.size(); 
	
	//stime block
	int stime = accumulate(time.begin(), time.end(), 0); 
	
	//sgather block
	int sgather = accumulate(history_gather.begin(), history_gather.end(), 0); 
	
	//timextime block, would prefer to do this in vector<int> time rather than toss into new vector
	//would have to move below stxg init if that happened
	std::vector<int> timextime; 
	for (int i=0; i<timesize; i++)
		timextime.push_back(time.at(i)*time.at(i));
	int stxt = accumulate(timextime.begin(), timextime.end(), 0);

	//timexgather block, this one needs the new vector, might still be a quicker way to do it
	std::vector<int> timexgather;
	for (int i=0; i<historysize; i++)
		timexgather.push_back(history_gather.at(i)*time.at(i));
	int stxg = accumulate(timexgather.begin(), timexgather.end(), 0); 
	
	//this can result in a double, not too concerned about losing tail
	int top = ((timesize * stxg)-(stime*sgather));
	int bottom = ((timesize * stxt)-(stime*stime));
	int slope = top/bottom;

	//standard deviation block
	std::vector<int> gather_devs;
	for (int i=0; i<historysize; i++) {
		int left = history_gather.at(i) - mean;
		gather_devs.push_back(left * left);
	}

	double dev_sum = accumulate(gather_devs.begin(), gather_devs.end(), 0);
	double avg_dev_sum = dev_sum/historysize;
	int std_dev = sqrt(avg_dev_sum);

	//sds is a struct that holds slope and std dev 
	sds.slope = slope;
	sds.std_dev = std_dev;
	sds.average = mean;
}


get_avg_gather() (the code for it follows) is the only function call in get_history_reg(). It gets called first. When I look through the call stack, here's what I see:

1
2
3
4
5
6
>	robo2.exe!std::_Vector_const_iterator<int,std::allocator<int> >::operator+=(int _Off = 2) Line 163	C++
 	robo2.exe!std::_Vector_iterator<int,std::allocator<int> >::operator+=(int _Off = 2) Line 375 + 0xc bytes	C++
 	robo2.exe!std::_Vector_iterator<int,std::allocator<int> >::operator+(int _Off = 2) Line 382 + 0x12 bytes	C++
 	robo2.exe!std::_Copy_opt<std::_Vector_iterator<int,std::allocator<int> >,std::_Vector_iterator<int,std::allocator<int> >,std::random_access_iterator_tag>() Line 2504 + 0xe bytes	C++
 	robo2.exe!std::copy<std::_Vector_iterator<int,std::allocator<int> >,std::_Vector_iterator<int,std::allocator<int> > >() Line 2563 + 0x11e bytes	C++
 	robo2.exe!Food::get_avg_gather(bool  = false) Line 40 + 0xb9 bytes	C++


The problem is I'm only halfway certain what most of that means! But it seems to indicate that the problem occurs somewhere in get_avg_gather(), or at least that there's no function call that follows it. Here's the get_avg_gather():

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
int Food::get_avg_gather(bool isoptimist) {
	const int historysize =history_gather.size();
	if (historysize ==0)
		return (0);
	std::vector<int> local_history;

	copy(history_gather.begin(), history_gather.end(), local_history.begin());

	sort (local_history.begin(), local_history.end());
	const long sum = accumulate (history_gather.begin(), history_gather.end(), 0);
	
	mean = sum/historysize;
	int median =0, arg =0;
	
	if (historysize%2 !=0)
		median = local_history.at((historysize/2)+1);
	else {
		arg = historysize/2;
		int left1 = local_history.at(arg);
		int left2 = local_history.at(arg+1);
		median = (left1 + left2)/2;
	}

	if (isoptimist ==0) 
		return (std::min(median, mean));
	else
		return (std::max(mean, median));
}


I think this might be the problem here:

 
copy(history_gather.begin(), history_gather.end(), local_history.begin());


All the debugger stuff seems to reference copying. This is the only copy in the function. I'm going to try writing the following code and see if it fixes the problem:

1
2
3
4
for (int i=0; i<historysize; i++){
int higath = history_gather.at(i);
local_history.push_back(higath);
}


Update:

So, that change did nothing. I now get the following error box:

1
2
3
4
An unhandled exception of type
'System.Runtime.InteropServices.SEHException' occurred in robo2.exe

Additional information: External component has thrown an exception.


Which is a little arcane. The call stack reads the following:

1
2
3
4
5
6
7

>	kernel32.dll!7c812afb() 	
 	[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]	
 	[Managed to Native Transition]	
 	robo2.exe!std::vector<int,std::allocator<int> >::_Xran() Line 1265 + 0x28 bytes	C++
 	robo2.exe!std::vector<int,std::allocator<int> >::at(unsigned int _Pos = 2) Line 755	C++
 	robo2.exe!Food::get_avg_gather(bool  = false) Line 58 + 0xf bytes	C++


Which is a little more arcane. I'm guessing it means the problem is somewhat lower than the copy function, but I dunno. Googling produces nothing other than the potential that I've left out a library, which isn't likely since this is being run out of the IDE.

Update:

A chance peek at Output showed me this little bit:
 
First-chance exception at 0x7c812afb in robo2.exe: Microsoft C++ exception: std::out_of_range at memory location 0x0012eae0..


Which I think I understand. And it made a lot more sense when it led me to this:
1
2
3
4
static void _Xran()
		{	// report an out_of_range error
		_THROW(out_of_range, "invalid vector<T> subscript");
		}


I'm betting it has something to do with this section:

1
2
3
4
5
6
7
8
9
10
	if (historysize%2 !=0){
		int loc = (historysize/2)+1;
		median = local_history.at(loc);
	}
	else {
		arg = historysize/2;
		int left1 = local_history.at(arg);
		int left2 = local_history.at(arg+1);
		median = (left1 + left2)/2;
	}


My money is on it being the first one. It divides by 2, then adds 1 -- SOP for getting a median, but since vector positions start at zero, if it divides 2/2=1, and then adds 1 then it'll be trying to get somevector.at(2) when there are only two elements it'll get, well, an error. This MUST be it! My LORD this is insidious as hell! No wonder people pull their hair out over logic errors!
Last edited on
I realize this thread is me talking to myself, but I'm so FREAKING PUMPED RIGHT NOW!

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
int Food::get_avg_gather(bool isoptimist) {
	const int historysize =history_gather.size();
	if (historysize ==0)
		return (0);

	std::vector<int> local_history;

	for (int i=0; i<historysize; i++){
		int higath = history_gather.at(i);
		local_history.push_back(higath);
	}

	sort (local_history.begin(), local_history.end());
	long sum = accumulate (history_gather.begin(), history_gather.end(), 0);
	
	mean = sum/historysize;
	int median =0, arg =0;
	
	if (historysize <3)
		return (mean);

	else if (historysize%2 !=0){
			int loc = (historysize/2)+1;
			median = local_history.at(loc);
		}
	else {
		arg = historysize/2;
		int left1 = local_history.at(arg);
		int left2 = local_history.at(arg+1);
		median = (left1 + left2)/2;
		}

	if (isoptimist ==0) 
		return (std::min(median, mean));
	else
		return (std::max(mean, median));
}


Rewriting this function with a size check made everything clear. The problem was that I was trying to find the median of a set of two, which just wasn't going to happen. The problem might crop up again because of my implementation, but I'm going to test it rigorously to make sure that that won't happen!

In any event WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!
Last edited on
Topic archived. No new replies allowed.