PPP2 Chapter 10 Exercise 6 - "vector iterator not incrementable"?

I'm getting a debug assertion error when I try to run my implementation of the Roman_int class exercise program. The debug assertion error is as I put in the title of this thread, "vector iterator not incrementable".

It's triggered from line 102 of this code in the <vector> header (line 9 here since I'm not bringing in the whole header):
1
2
3
4
5
6
7
8
9
10
11
	_Myiter& operator++()
		{	// preincrement
 #if _ITERATOR_DEBUG_LEVEL == 2
		const auto _Mycont = static_cast<const _Myvec *>(this->_Getcont());
		if (_Mycont == 0
			|| _Ptr == nullptr_t{}
			|| _Mycont->_Mylast <= _Ptr)
			{	// report error
			_DEBUG_ERROR("vector iterator not incrementable");
			_SCL_SECURE_OUT_OF_RANGE;
			}


This is my 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
// chapter10ex6.cpp : Defines the entry point for the console application.
// Osman Zakir
// 2 /17 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 10 Exercise 6
// Exercise Specifications:
/**
 * Define a Roman_int class for holding Roman numerals (as int s) with a
 * << and >> . Provide Roman_int with an as_int() member that returns the
 * int value, so that if r is a Roman_int , we can write cout << "Roman"
 * << r << " equals " << r.as_int() << '\n';.
 */

#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <fstream>

class Roman_int
{
private:
	std::string roman_num;
public:
	int as_int(const std::string roman);
	const std::string &get_r_num() const { return roman_num; }
	void set_r_num(const std::string s_val) { roman_num = s_val; }
};

std::istream& operator>>(std::istream &is, Roman_int &r);
std::ostream& operator<<(std::ostream &os, const Roman_int &r);
inline void error(const std::string& s, const std::string& s2);
inline void error(const std::string& s);

int main()
{
	std::cout << "Please enter a roman numeral within the range 1 through 300: ";
	Roman_int r;
	std::cin >> r;
	std::cout << "Roman numeral " << r << " as an Arabic numeral is "
		<< r.as_int(r.get_r_num()) << '\n';
}

int Roman_int::as_int(const std::string roman)
{
	std::cout << "Please enter input file name: ";
	std::string iname;
	std::cin >> iname;
	std::ifstream ist{ iname };
	try
	{
		if (!ist)
		{
			error("can't open input file ", iname);
		}
	}
	catch (const std::runtime_error &e)
	{
		std::cerr << "error: " << e.what() << '\n';
	}
	
	std::vector<std::string> roman_nums{ 300 };
	for (auto &num : roman_nums)
	{
		getline(ist, num);
		roman_nums.push_back(num);
	}

	size_t index = 0;
	for (size_t i = 0; i < roman_nums.size(); ++i)
	{
		if (roman == roman_nums[i])
		{
			index = i + 1;
		}
	}

	return index;
}

std::istream& operator>>(std::istream &is, Roman_int &r)
{
	std::string roman_s;
	is >> roman_s;
	r.set_r_num(roman_s);
	return is;
}

std::ostream& operator<<(std::ostream &os, const Roman_int &r)
{
	os << r.get_r_num() << '\n';
	return os;
}

inline void error(const std::string& s)
{
	throw std::runtime_error(s);
}

inline void error(const std::string& s, const std::string& s2)
{
	error(s + s2);
}
Last edited on
You can't add elements to the vector while iterating over it using a range-based for loop.
The exercise doesn't say anything about reading from a file.
AFAI understand your program should be able to convert a roman number to an int, sth. like

Please enter a roman numeral: XIV
Roman numeral XIV equals 14 as int.
I know. The file is my way of getting the roman numerals so I don't have to type them all out into a vector on my own. It didn't work right, though. CL is being outputted as 451 as an int.

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
// chapter10ex6.cpp : Defines the entry point for the console application.
// Osman Zakir
// 2 /17 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 10 Exercise 6
// Exercise Specifications:
/**
 * Define a Roman_int class for holding Roman numerals (as int s) with a
 * << and >> . Provide Roman_int with an as_int() member that returns the
 * int value, so that if r is a Roman_int , we can write cout << "Roman"
 * << r << " equals " << r.as_int() << '\n';.
 */

#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <fstream>

class Roman_int
{
private:
	std::string roman_num;
public:
	int as_int(const std::string roman);
	const std::string &get_r_num() const { return roman_num; }
	void set_r_num(const std::string s_val) { roman_num = s_val; }
};

std::istream& operator>>(std::istream &is, Roman_int &r);
std::ostream& operator<<(std::ostream &os, const Roman_int &r);
inline void error(const std::string& s, const std::string& s2);
inline void error(const std::string& s);

int main()
{
	std::cout << "Please enter a roman numeral within the range 1 through 300: ";
	Roman_int r;
	std::cin >> r;
	std::cout << "Roman numeral " << r << " as an Arabic numeral is "
		<< r.as_int(r.get_r_num()) << '\n';
}

int Roman_int::as_int(const std::string roman)
{
	std::cout << "Please enter input file name: ";
	std::string iname;
	std::cin >> iname;
	std::ifstream ist{ iname };
	try
	{
		if (!ist)
		{
			error("can't open input file ", iname);
		}
	}
	catch (const std::runtime_error &e)
	{
		std::cerr << "error: " << e.what() << '\n';
	}
	
	std::vector<std::string> roman_nums{ 300 };
	std::string num;
	while (getline(ist, num))
	{
		roman_nums.push_back(num);
	}

	size_t index = 0;
	for (size_t i = 0; i < roman_nums.size(); ++i)
	{
		if (roman == roman_nums[i])
		{
			index = i + 1;
		}
	}

	return index;
}

std::istream& operator>>(std::istream &is, Roman_int &r)
{
	std::string roman_s;
	is >> roman_s;
	r.set_r_num(roman_s);
	return is;
}

std::ostream& operator<<(std::ostream &os, const Roman_int &r)
{
	os << r.get_r_num() << '\n';
	return os;
}

inline void error(const std::string& s)
{
	throw std::runtime_error(s);
}

inline void error(const std::string& s, const std::string& s2)
{
	error(s + s2);
}


Edit: Okay, never mind. I figured out the problem in my as_int() function. It should be like this:
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
int Roman_int::as_int(const std::string &roman)
{
	std::cout << "Please enter input file name: ";
	std::string iname;
	std::cin >> iname;
	std::ifstream ist{ iname };
	try
	{
		if (!ist)
		{
			error("can't open input file ", iname);
		}
	}
	catch (const std::runtime_error &e)
	{
		std::cerr << "error: " << e.what() << '\n';
	}
	
	std::vector<std::string> roman_nums;
	std::string num;
	while (getline(ist, num))
	{
		roman_nums.push_back(num);
	}

	int arabic_num = 0;
	for (size_t i = 0; i < roman_nums.size(); ++i)
	{
		if (roman == roman_nums[i])
		{
			arabic_num = i + 1;
		}
	}
	return arabic_num;
}


What would be a good way to do this without having to pass a std::string representing a Roman numeral to it as input?
Last edited on
The file is my way of getting the roman numerals so I don't have to type them all out into a vector on my own.

Why do you need a vector? Do you do a different exercise?
Also it seems do don't understand to problem of converting a roman number to an int. A roman number is sth. like XIV and you need to find a way to produce the int 14.

http://www.geeksforgeeks.org/converting-roman-numerals-decimal-lying-1-3999/
I used a vector for the mapping. It's the same exercise. The output is correct right now. I'll look at that link after this post (I hope there's a better to convert a Roman numeral to an int shown in there). For now, I'll just post the code I have 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
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
// chapter10ex6.cpp : Defines the entry point for the console application.
// Osman Zakir
// 2 /17 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 10 Exercise 6
// Exercise Specifications:
/**
 * Define a Roman_int class for holding Roman numerals (as int s) with a
 * << and >> . Provide Roman_int with an as_int() member that returns the
 * int value, so that if r is a Roman_int , we can write cout << "Roman"
 * << r << " equals " << r.as_int() << '\n';.
 */

#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <fstream>
#include "cust_std_lib_facilities.h"

class Roman_int
{
private:
	std::string roman_num;
public:
	int as_int(const std::string &roman);
	const std::string &get_r_num() const { return roman_num; }
	void set_r_num(const std::string s_val) { roman_num = s_val; }
};

std::istream& operator>>(std::istream &is, Roman_int &r);
std::ostream& operator<<(std::ostream &os, const Roman_int &r);

int main()
{
	using namespace std;
	cout << "Please enter a roman numeral within the range 1 through 300: ";
	Roman_int r;
	cin >> r;
	cout << "Roman numeral " << r << " as an int is " 
		<< r.as_int(r.get_r_num()) << '\n';
	keep_window_open();
}

int Roman_int::as_int(const std::string &roman)
{
	using namespace std;
	cout << "Please enter input file name: ";
	string iname;
	cin >> iname;
	ifstream ist{ iname };
	try
	{
		if (!ist)
		{
			error("can't open input file ", iname);
		}
	}
	catch (const runtime_error &e)
	{
		std::cerr << "error: " << e.what() << '\n';
	}
	
	vector<string> roman_nums;
	string num;
	while (getline(ist, num))
	{
		roman_nums.push_back(num);
	}

	int arabic_num = 0;
	for (size_t i = 0; i < roman_nums.size(); ++i)
	{
		if (roman == roman_nums[i])
		{
			arabic_num = i + 1;
		}
	}
	return arabic_num;
}

std::istream& operator>>(std::istream &is, Roman_int &r)
{
	using namespace std;
	string roman_s;
	is >> roman_s;
	r.set_r_num(roman_s);
	return is;
}

std::ostream& operator<<(std::ostream &os, const Roman_int &r)
{
	os << r.get_r_num() << '\n';
	return os;
}


I took the overloads for error() and keep_window_open() and put them into a custom header. If you think I should also add some other stuff from std_lib_facilities.h as well, please let me know. I'm using VS2015 and apparently Microsoft doesn't support C++11 inheriting constructors according to a comment Stroustrup added to the header file here:
1
2
3
4
5
6
7
8
9
10
11
#ifdef _MSC_VER
	// microsoft doesn't yet support C++11 inheriting constructors
	Vector() { }
	explicit Vector(size_type n) :std::vector<T>(n) {}
	Vector(size_type n, const T& v) :std::vector<T>(n,v) {}
	template <class I>
	Vector(I first, I last) : std::vector<T>(first, last) {}
	Vector(initializer_list<T> list) : std::vector<T>(list) {}
#else
	using std::vector<T>::vector;	// inheriting constructor
#endif 


Does this still apply? Should I keep this in my custom header, too?

Edit: Alright, thanks for giving me that link. I used the functions from that and it works much better. Why is my output on two separate lines, though? When I say cout << "Roman numeral " << r << " as an int is " << r.as_int(r.get_r_num()) << '\n'; the result is


Roman numeral <insert Roman Numeral here>
as an int is <insert int value here>


It's separated like that.
Last edited on
Maybe he was using an older version of Visual Studio. Here is a list of features:
https://msdn.microsoft.com/en-us/library/hh567368.aspx

Why is my output on two separate lines, though? When I say cout << "Roman numeral " << r << " as an int is " << r.as_int(r.get_r_num()) << '\n'; the result is


You have one '\n' in your output operator as well.
I guess I already fixed that.
cout << "Roman numeral " << r << " as an int is " << r.as_int(r.get_r_num()) << '\n';

But when I run it now, it still does that.

Edit: Sorry, didn't understand at first. Fixed the output operator.
Last edited on
Topic archived. No new replies allowed.