Reputation: 3451
It has been a while that I've written code in C/C++, and I've already found an alternative solution to my problem, but I would like to know why the original code doesn't work.
I have a test class which basically only stores a string.
class test {
private:
std::string name;
public:
test(std::string name) : name(name) {};
std::string get_name() { return name; }
};
In main
I have a vector which I at one point fill with test
objects. The code below simulates irregular usage of the vector vect
.
int main(void) {
std::vector<test *> vect;
std::vector<test *>::iterator i;
//* Comment this for a working example
std::cout << "Searching empty vector" << std::endl;
i = *(_is_in_vector(vect, std::string("test 3")));
if (i == vect.end()) {
std::cout << "Nothing found" << std::endl;
} // */
vect.push_back(new test("test 1"));
vect.push_back(new test("test 2"));
vect.push_back(new test("test 3"));
std::cout << "All:" << std::endl;
i = *(_is_in_vector(vect, std::string("test 3")));
if (i != vect.end()) {
std::cout << "Erase " << (*i)->get_name() << std::endl;
vect.erase(i);
delete *i;
}
i = *(_is_in_vector(vect, std::string("test 3")));
if (i == vect.end()) {
std::cout << "Nothing found" << std::endl;
}
std::cout << "Left:" << std::endl;
for (i = vect.begin(); i!=vect.end(); ++i) {
std::cout << (*i)->get_name() << std::endl;
delete *i;
}
vect.clear();
return 0;
}
Because searching in the vector for a test
object happens multiple times, I've created the function _is_in_vector
that searches a test
object and returns the iterator to it.
static std::vector<test *>::iterator * _is_in_vector(std::vector<test *> &vect, std::string find) {
std::string identity = find;
static std::vector<test *>::iterator i = vect.begin();
std::cout << "Vect size: " << vect.size() << std::endl;
for (i; i != vect.end(); ++i) {
std::string tmp = (*i)->get_name(); /* Segmentation fault after filling vector*/
if (0 == identity.compare(tmp)) break;
}
return &i;
}
The problem is that the code above works when I comment out the Searching empty vector
part in main
. Once the vector is filled with test
objects, I call _is_in_vector
a second time. The vector in this function does have three entries, but (*i)
all point to NULL
.
Output:
Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Segmentation fault
Expected output:
Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Erase test 3
Vect size: 2
Nothing found
Left:
test 1
test 2
Upvotes: 0
Views: 610
Reputation: 44268
First of all it is unclear why you need to store test
objects by pointer but not by value. If you do need it use smart pointer.
As for your problem, why do you return pointer to an iterator? This is the root cause of your problem - to make &i
legal to return you made it static
, but static
local variables initialized only once and do not change value btw calls - so after first call it pointed to an element in the vector, but after that you added elements and invalidated all iterators including static i
hense the segmentation fault. So fix is simple - return iterator by value and make i
non static but regular, it is light and it is totally fine to do so.
PS Identifiers starting with _
are illegal in global context, details can be found here What are the rules about using an underscore in a C++ identifier?
So your function actually should look like this:
static std::vector<test *>::iterator is_in_vector( std::vector<test *> &vect, const std::string &find)
{
return std::find_if( vect.begin(), vect.end(), [find]( test *p ) {
return p->get_name() == find;
} );
}
assuming the vector should never hold nullptr
, if it is the case or to play safe change condition to:
return p && p->get_name() == find;
Upvotes: 5