Adding Range Based Support to Class

Sep 29, 2020 at 9:23am
I am trying to fix, so that range-based for loops are supported with my custom class. I am also trying to search for an employee, but my search gives me wrong results even when strings match?

What's wrong here?

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
#include <iostream>
#include <string>
#include <iterator>

class Employee
{
public:
  Employee () = default;
  Employee (std::string name, std::string address) {
      this->name = name;
      this->address = address;
  }

  std::string getName ()
  {
    return this->name;
  }
  std::string getAddress ()
  {
    return this->address;
  }

private:
  std::string name = "";
  std::string address = "";

};

class EmployeeArray
{
public:
  EmployeeArray (int max):max (max)
  {
    employees = new Employee[max];
  }

  void add (const Employee * e)
  {
    employees[current_total] = *e;
    current_total++;
  }

  void remove (Employee * e)
  {
    for (Employee * ee = employees; ee != employees + current_total; ++ee)
      {
    	if (ee == e) {
    	    delete ee;
    	    ee = nullptr;
    	    current_total--;
    	    std::cout << "Employee was successfully deleted" << std::endl;
    	}
      }
      
      std::cout << "Employee was not deleted" << std::endl;
  }

  Employee *SearchWithName (std::string name)
  {
    for (Employee * e = employees; e != employees + current_total; ++e)
    {
		if (e->getName() == name) { return e; }
    }
    return NULL;
  }

private:
  Employee * employees;
  int max = 0;
  int current_total = 0;
};

int
main ()
{
  Employee *e =
    new Employee ("Richard Johnson", "1801 E 10th St Pueblo, CO 81001");

  EmployeeArray *empArr = new EmployeeArray (2);
  empArr->add (e);
  empArr->
    add (new Employee ("David Paras", "15 Spring St Rear Peabody, MA 01960"));

  std::cout << (empArr->SearchWithName ("lol") !=
		NULL ? "Employee found!" : "This employee couldn't be found!")
    << std::endl;
  
  for(const Employee &p: *empArr)
  {
      std::cout << p->getName() << std::endl;
  }
  return 0;
}
Sep 29, 2020 at 9:35am
Your remove (...) function is wrong.

I am also trying to search for an employee, but my search gives me wrong results even when strings match?
What does it mean. In my test the employee is found when using the right name.

You can't have range based for loop with dynamic arrays.
Sep 29, 2020 at 10:05am
For a class to work with range-based for loop, the class needs to define:

begin()
end()
operator++() (pre-increment) if needed
operator*() (dereference) if needed
operator->() (pointer reference) if needed
operator !=() if needed
Last edited on Sep 29, 2020 at 12:21pm
Sep 29, 2020 at 10:11am
@coder777, I am noticing that I cannot perform remove. Why is it wrong?

I am trying to provide: search function, to full match or partial match.
Sep 29, 2020 at 10:12am

begin()
end()
operator++() (pre-increment)
operator*() (dereference)
operator->() (pointer reference)


Where should I put that?
Sep 29, 2020 at 10:58am
I am noticing that I cannot perform remove. Why is it wrong?
You are trying to delete a field of an array which means undefined behavior. When the order isn't important you can do this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  void remove (Employee * e)
  {
    for (Employee * ee = employees; ee != employees + current_total; ++ee)
      {
    	if (ee == e) {
    	    current_total--;
    	    *ee = employees[current_total]; // Note: this overwrites the found element with the last
    	    std::cout << "Employee was successfully deleted" << std::endl;
    	    return; // Note: This prevents writing beyond the end
    	}
      }
      
      std::cout << "Employee was not deleted" << std::endl;
  }
It's also a bit strange that you use a pointer for removing.

Actually line 77/82 create memory leaks because on line 39 you just copy the contents of the objects.

to full match or partial match.
For this you may use the find function of the string. See:

http://www.cplusplus.com/reference/string/string/find/
Sep 29, 2020 at 11:53am
Consider something like this (which fixes some of the problems in the first post). To support range-based for loop, you need to understand iterators.

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
#include <iostream>
#include <string>

class Employee
{
public:
	Employee() = default;
	Employee(const std::string& n, const std::string& a) : name(n), address(a) {}

	std::string getName() const { return name; }
	std::string getAddress() const { return address; }

private:
	std::string name;
	std::string address;
};

class EmployeeArray
{
public:
	EmployeeArray() = default;
	EmployeeArray(int m) : max(m), employees(new Employee[m] {}) {}

	~EmployeeArray()
	{
		delete[] employees;
	}

	bool add(const Employee& e)
	{
		if (current_total < max) {
			employees[current_total++] = e;
			return true;
		}

		return false;
	}

	auto begin() const
	{
		return curpos = employees;
	}

	auto end() const
	{
		return employees + current_total;
	}

	auto operator++() const
	{
		++curpos;
		return *this;
	}

	auto operator*() const
	{
		return *curpos;
	}

	bool remove(const Employee& e)
	{
		for (auto ee = begin(); ee != end(); ++ee)
			if (ee->getName() == e.getName()) {
				*ee = employees[--current_total];
				return true;
			}

		return false;
	}

	Employee* SearchWithName(const std::string& name) const
	{
		for (auto e = begin(); e != end(); ++e)
			if (e->getName() == name)
				return e;

		return nullptr;
	}

	void display() const {
		for (auto e = begin(); e != end(); ++e)
			std::cout << e->getName() << std::endl;
	}

private:
	Employee* employees = nullptr;
	int max = 0;
	int current_total = 0;
	mutable Employee* curpos = nullptr;
};

int main()
{
	const auto e = Employee("Richard", "1801 E 10th St Pueblo, CO 81001");
	auto empArr = EmployeeArray(5);

	empArr.add(e);
	empArr.add(Employee("David", "15 Spring St Rear Peabody, MA 01960"));
	empArr.add(Employee("lol", "15 Spring St Rear Peabody, MA 01960"));

	//empArr->display();
	for (const auto& ee : empArr)
		std::cout << ee.getName() << std::endl;

	std::cout << (empArr.SearchWithName("lol") != nullptr ? "Employee found!" : "This employee couldn't be found!") << std::endl;
	std::cout << (empArr.remove(e) ? "Employee deleted!" : "Not deleted") << std::endl;
	std::cout << (empArr.remove(*(empArr.SearchWithName("lol"))) ? "Employee deleted!" : "Not deleted") << std::endl;

	//empArr->display();
	for (const auto& e : empArr)
		std::cout << e.getName() << std::endl;
}


which displays:


Richard
David
lol
Employee found!
Employee deleted!
Employee deleted!
David

Last edited on Sep 29, 2020 at 12:13pm
Sep 29, 2020 at 12:10pm
@seeplus
The operator++ and operator* are unnecessary and so is curpos.
Sep 29, 2020 at 12:21pm
@coder777

True in this case as the type returned by begin() is just a pointer - so doesn't need operator overloading. If a non-pointer if returned then they are needed.

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
#include <iostream>
#include <string>

class Employee
{
public:
	Employee() = default;
	Employee(const std::string& n, const std::string& a) : name(n), address(a) {}

	std::string getName() const { return name; }
	std::string getAddress() const { return address; }

private:
	std::string name;
	std::string address;
};

class EmployeeArray
{
public:
	EmployeeArray() = default;
	EmployeeArray(int m) : max(m), employees(new Employee[m] {}) {}

	~EmployeeArray()
	{
		delete[] employees;
	}

	bool add(const Employee& e)
	{
		if (current_total < max) {
			employees[current_total++] = e;
			return true;
		}

		return false;
	}

	auto begin() const
	{
		return employees;
	}

	auto end() const
	{
		return employees + current_total;
	}

	bool remove(const Employee& e)
	{
		for (auto ee = begin(); ee != end(); ++ee)
			if (ee->getName() == e.getName()) {
				*ee = employees[--current_total];
				return true;
			}

		return false;
	}

	Employee* SearchWithName(const std::string& name) const
	{
		for (auto e = begin(); e != end(); ++e)
			if (e->getName() == name)
				return e;

		return nullptr;
	}

	void display() const {
		for (auto e = begin(); e != end(); ++e)
			std::cout << e->getName() << std::endl;
	}

private:
	Employee* employees = nullptr;
	int max = 0;
	int current_total = 0;
};

int main()
{
	const auto e = Employee("Richard", "1801 E 10th St Pueblo, CO 81001");
	auto empArr = EmployeeArray(5);

	empArr.add(e);
	empArr.add(Employee("David", "15 Spring St Rear Peabody, MA 01960"));
	empArr.add(Employee("lol", "15 Spring St Rear Peabody, MA 01960"));

	//empArr->display();
	for (const auto& ee : empArr)
		std::cout << ee.getName() << std::endl;

	std::cout << (empArr.SearchWithName("lol") != nullptr ? "Employee found!" : "This employee couldn't be found!") << std::endl;
	std::cout << (empArr.remove(e) ? "Employee deleted!" : "Not deleted") << std::endl;
	std::cout << (empArr.remove(*(empArr.SearchWithName("lol"))) ? "Employee deleted!" : "Not deleted") << std::endl;

	//empArr->display();
	for (const auto& e : empArr)
		std::cout << e.getName() << std::endl;
}

Sep 29, 2020 at 12:35pm
If a non-pointer if returned then they are needed.
They are needed in the iterator like objects return by begin()/end() not the container itself.
Topic archived. No new replies allowed.