Is there a way to set an iterator "one before" the begging?

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
	//Verifying Candidates using the rest of the strings, removing those that are not present on any of untested strings.
	for(vector<string>::iterator cand_itr = candidates.begin(); cand_itr != candidates.end(); ++cand_itr)
		label1:
		for(vector<string>::iterator song_itr = song_names.begin(); song_itr != song_names.end(); ++song_itr)
			if(song_itr->find(*cand_itr) == static_cast<size_t>(-1))
				{
					if(cand_itr == candidates.begin())
						{
							candidates.erase(cand_itr);
							cand_itr = candidates.begin();

							if(cand_itr == candidates.end())
								return false;

							goto label1; //	cand_itr is set to begin, this makes sure that it won't get incremented
						}				// Discarding the tests for this element.
							
					vector<string>::iterator tmp = cand_itr-1; //-1 because it will be incremented in the 1st for.
					candidates.erase(cand_itr);				   //This way it will point to the next element. Not the after the next element.
					cand_itr = tmp;


					
					break;
				}


I want to get ride of the non sense in lines 12 and 15. The easiest way to do that would be to set cand_itr one before the beggining and breaking the inner for, since it will get incremented in the header of the outer for.

The obvious problem is that it will throw an exception if I attemp to. Is there anyway to prevent it from throwing the exception?

EDIT: Actually if that was possible I could get ride of the entire if statement I guess.
Last edited on
Could you please explain what is supposed to happen with an example.

The presence of goto and label is a bad sign!
1
2
3
4
5
1 - hotPub__skdma - -- Madonna - song title is nice.mp3
2 - hotPub__skdma - -- Madonna - title  sd is nice.mp3
3 - hotPub__skdma - -- Madonna - hello title .mp3
4 - hotPub__skdma - -- Madonna - come tit4le to life.mp3
5 - hotPub__skdma - -- Madonna - title You are ugly.mp3


First part of the code (which I didn't post here) finds substrings that are equal by comparing the first two strings given.

In this case it will push back "- hotPub__skdma - -- Madonna - ", " is nice" and " title " into candidates.

This works fine.

The section of code which I posted here is suposed (and works as suposed, I just don't like the way I had to wrote it) to remove from candidates substrings that are not present in the next strings.
The next step being to compare the 2nd and 3rd string, which would give just

"- hotPub__skdma - -- Madonna - " and " title "

which means " is nice" need to be removed from candidates?

So you're expecting "- hotPub__skdma - -- Madonna - " and " title " as the final result?

(I assume tit4le is a typo?)
The answer to your question :
"Is there a way to set an iterator "one before" the begging?"
is no!

But you don't have to.

You just need to stop automatically incrementing the iterator on each loop, and only call ++ when you don't call erase.

1
2
3
4
5
6
7
8
9
10
11
    typedef vector<string>::iterator iter_t;

    for(iter_t cand_itr = candidates.begin(); cand_itr != candidates.end(); /*no incr*/)
    {
        ... set shouldErase to true if you need to erase ...

        if(shouldErase)
            cand_itr = candidates.erase(cand_itr);
        else
            ++cand_itr;
    }


Andy

P.S. Or you could use a while loop?
Last edited on
"titl4e " is not a typo, but yes that's how it should work (and works). The only candidate for this example is " - hotPub__skdma - -- Madonna - ".

Last night I did give it a shot trying that method but I was getting all kind of exceptions thrown. I'll give a try again tonight.

Thank's for the input. :)
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
	bool increment = true;

	//Verifying Candidates using the rest of the strings, removing those that are not present on any of untested strings.
	for(vector<string>::iterator cand_itr = candidates.begin(); cand_itr != candidates.end(); )
		{
			for(vector<string>::iterator song_itr = song_names.begin(); song_itr != song_names.end(); ++song_itr)
				if(song_itr->find(*cand_itr) == static_cast<size_t>(-1)) //If string does not contain candidate:
					{
						if(cand_itr == candidates.begin())
							{
								candidates.erase(cand_itr);
								cand_itr = candidates.begin();

								if(cand_itr == candidates.end())
									return false;
							
								increment = false;
								break;

							
							}
							
						vector<string>::iterator tmp = cand_itr - 1; //-1 because it will be incremented afterwords
						candidates.erase(cand_itr);					//This way it will point to the next element. Not the after the next element.
						cand_itr = tmp;
					
						break;
					}
			
			if(increment)
				++cand_itr;

			increment = true;
		}


I solved the problem this way. Although I believe it is slightly slower like this, it's definitly more readable. (Drawbacks: one more variable used, one more comparation made)
Does this do what you want?

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
    //Verifying Candidates using the rest of the strings, removing those
    // that are not present on any of untested strings.

    typedef vector<string>::iterator       iter_t;
    typedef vector<string>::const_iterator const_iter_t;

    const const_iter_t song_begin_iter = song_names.begin();
    const const_iter_t song_end_itr    = song_names.end();

    for(iter_t cand_itr = candidates.begin(); cand_itr != candidates.end(); /*no incr*/)
    {
        bool should_erase = false;

        for(const_iter_t song_itr = song_begin_iter; song_itr != song_end_itr; ++song_itr)
        {
            const string& song = *song_itr;
            if(song.find(*cand_itr) == song.npos)
            {
                should_erase = true;
                break;
            }
        }

        if(should_erase)
            cand_itr = candidates.erase(cand_itr);
        else
            ++cand_itr;
    }

    return !candidates.empty();

¿ set_intersection ?
Not here, unfortunately. The inner loop is looking for a substring (line 17) rather than just a match. If it was just looking for equal strings, the set approach would have been cool.
It does indeed. Way simplier ;)
You could use an algorithm? Or more!
Last edited on
What do you mean?
For example, you could replace the inner loop with find_if()

http://www.cplusplus.com/reference/algorithm/find_if/

The contents of the loop body would need to be moved to create a suitable predicate functor.

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
class FindSubstr
: unary_function<bool, const string&>
{
private:
	const string& m_candidate;

public:
	FindSubstr(const string& candidate)
	: m_candidate(candidate)
	{
	}

	FindSubstr(const FindSubstr& that)
	: m_candidate(that.m_candidate)
	{
	}

	bool operator()(const string& song) const
	{
		return (song.find(m_candidate) == song.npos);
	}

	FindSubstr& operator=(const FindSubstr& that);
};

bool ShouldErase(const vector<string>& song_names , const string& candidate)
{
	typedef vector<string>::const_iterator const_iter_t;

	const const_iter_t song_begin_iter = song_names.begin();
	const const_iter_t song_end_itr    = song_names.end();

	const_iter_t song_itr = find_if(song_begin_iter, song_end_itr, FindSubstr(candidate));

	return (song_itr != song_end_itr);
}
Oh ok, you were talking about stl algorithms. I've not studied them yet.

I've gone through "C++ without fear" but it didn't even introduced the stl or templates. I'm now going through "C++ Primer 4th Ed.", stl algorithms are the next chapter. :)
Given how scary algorithms can get, I'm not surprised the "without fear" book omitted them!
Ahah good point ;P

Anyways this is going off-topic, soon enough someone will be here to shoot us for this.

Thanks for the input,

Hugo Ribeira
Topic archived. No new replies allowed.