I am having a little bit of trouble with finding a way to erase a value from a vector of pointer.
I have a vector std::vect<MyClass*> myVect which contains pointers to objects o1, o2,... in a specific order. I am having a bit of trouble to find how to delete the entry of one specific object, for example o1
I tried
void remove(MyClass C)
{
myVect.erase( std::find_if( myVect.begin(), myVect.end(), [&](MyClass* W)
{return &C == W;} ) );
}
but my bool lambda never returns true (verified with assert) . Is there something I am doing wrong? (I must say that I am not really familiar with Lambda functions/tors)
Thank you very much!
Your function accepts a MyClass by value as C, so it's always working with a freshly made instance in the function's local scope.
Your test function is checking &C == W;, but it's impossible for the address of C to match the address stored in the vector (unless remove added it earlier).
If you really want the test to be by address, you probably want to accept your argument by reference, void remove(MyClass& C) in which case some other part of your code could pass an existing object by reference whose pointer might be in the vector.
More likely, you want the test to be by value, in which case, for efficiency, you probably want code more like this:
void remove(const MyClass& C) // Receive by const reference to avoid pointless copy
{
// Testing C == *W tests the value pointed to, not the pointers themselves
myVect.erase( std::find_if( myVect.begin(), myVect.end(), [&](MyClass* W)
{return C == *W;} ) );
}
Related
I have a method, which i want to execute differently depending on if the passed variable is an element of a vector or not, like for example:
void method(int a){
if (/*a is an element of a vector*/) //do one thing
else //do another thing
}
and then in main:
vector<int> a;
a.pushback(1);
int b = 1;
method(a[0]); // does one thing
method(b); // does the other thing
What is the simplest way to do that?
Well, for all cases this is impossible, because it actually requires your function to look at how it is executed, and there is no such thing in C++. The hated eval() comes to mind.
But in a certain case, when your vector is a global entity, you could pass your variable by link instead of value. Then, you can check if it fits the space between the start and end of the desired vector. This is how it is done(not tested though, but should work)
vector<int> v;
//fill it somewhere somehow
void method(int& a)
{
int* beg = v.data();
int* end = beg + v.size();
int* val = &a;
if ((val >= beg) && (val < end))
{
//it is a part of vector
}
else
{
//it is not a part of vector
{
}
Problem is that you really shouldn't do it this way... As people in the comments said, it DOES look like an XY problem.
An int is an int. An int does not wear a label around its neck, telling everyone where it came from. When an int is passed to a function, there is nothing that specifies where the int originates.
You should take this as an opportunity to learn about iterators, and implement an overloaded method that takes either an
void method(int);
for a parameter, or a
void method(std::vector<int>::iterator iter);
for a parameter (or, perhaps, a const_iterator), and invoke the alternative method() by passing it an iterator to the int in your vector.
For testing purposes I created a little unordered_set and tried to iterate over the set. The set holds an own class:
class Student {
private:
int matrNr;
string name;
public:
Student( const int& matrNr = 0, const string& name = "" )
: matrNr( matrNr ), name( name ) {}
void setNr( const int& matrNr ) {
this->matrNr = matrNr;
}
...
};
I inserted some elements and tried to change the objects during iteration:
unordered_set<Student, meinHash> meineHashTable;
meineHashTable.emplace( 12, "Fred" );
meineHashTable.emplace( 22, "Barney" );
meineHashTable.emplace( 33, "Wilma" );
for (int i = 0; i < meineHashTable.bucket_count(); i++) {
cout << "Bucketnummer: " << i << endl;
unordered_set<Student, meinHash>::local_iterator iter; // not constant?!?
if (meineHashTable.bucket_size( i ) > 0) {
for (iter = meineHashTable.begin( i ); iter != meineHashTable.end( i ); iter++) {
//const_cast<Student&>(*iter).setNr( 1234 ); //This does work
iter->setNr( 1234 ); //This does not work
}
}
else {
cout << "An empty Bucket" << endl;
}
}
I used a local_iterator (and not the const_local_iterator) but still I can't change the objects. For some reasons the iterator refers still to a constant object.
My question now: why is this so? If the normal iterator refers to a const object, what is the different between the const and the non-const iterator?
Tested with VisualStudio 2013 and minGW.
Thanks in advance for any help :-)
EDIT:
The Hash functor:
struct meinHash {
size_t operator()( const Student& s ) {
return s.getNr();
}
};
For finders of this topic in the future who have the same question, here is some example output if you change the matrNr with violent:
const_cast<Student&>(*iter).setNr( 5 );
and try to display it:
unordered_set<Student, meinHash>::local_iterator iter = meineHashTable.find( 5 );
iter->display();
you may get something like:
Bucketnummer: 0
An empty Bucket
Bucketnummer: 1
Matrikelnummer: 5
Name: Wilma
Bucketnummer: 2
An empty Bucket
Bucketnummer: 3
An empty Bucket
Bucketnummer: 4
Matrikelnummer: 5
Name: Fred
Bucketnummer: 5
An empty Bucket
Bucketnummer: 6
Matrikelnummer: 5
Name: Barney
Bucketnummer: 7
An empty Bucket
//The not wanted output ;-)
Matrikelnummer: -842150451
Name:
Both set and unordered_set have read-only keys. It's easy to see why this is the case - if the key value were to change, the data structure would have it filed in the wrong spot and you wouldn't be able to find it anymore.
Per your example, suppose your hash function simply returned the matrNr field. When the hash number changes, any lookup for 1234 will fail because there's nothing stored in that hash bucket.
It could be possible to change some part of the object that is not used in making the hash key, but that would lead to possible hard to track down bugs. The standards committee decided to eliminate that possibility by making the entire key const.
There are two ways around this restriction. The first is to split the key from the value and use a map or unordered_map instead. The second is to remove the item from the set and reinsert it after it's modified.
They value type of a set<K> is const K, and for a map<K, T> it is pair<const K, T>; ditto for the unordered versions.
An iterator gives you access to value_type &, and a const-iterator to a const value_type &. As you can see, neither iterator type can "undo" the constness of the key.
The reason the key is immutable is that it forms an integral part of the underlying data structure; changing the key would require a non-trivial internal rearrangement which would cause all sorts of problems (e.g. non-zero computational complexity (for element access!), and confused iterator ordering).
I had a similar problem and I was confused too. All the sources I looked at indicated that std::unordered_set::find can return a non-const iterator that dereferences to value_type&, which is non-const. On the other hand, all the above answers that state that changing field values within the instance changes its hash and therefore the way it is stored seem to make that impossible. It seems uncharacteristically "sloppy" for the spec to provide an interface that cannot be used, so there has to be a way to do something like what the questioner wants, and there is. You just have to give the compiler enough information to KNOW it's safe to provide you the non-const iterator. To further simplify the original question, we consider the following:
struct student {
std::string name;
double gpa;
// necessary for a decent member of a hash table. Compares all fields by default
bool operator==(const student& other) const = default;
student(const char* _name)
: name(_name)
, gpa(2.0) {}
};
std::unordered_set<student> student_set;
auto found = student_set.find("edgar"); // danger!! See note below
if (found != student_set.end()) {
found->gpa = 4.0; // <- compile failure here. "found" is of type const_iterator
}
If you just use the default std::hash<student>, it folds in all the data from the struct to create the hash - perhaps some combo of std::hash<std::string>(name) and std::hash<double>(gpa). Regardless of how it uses all this data, the compiler behaves as if it incorporates all the data and that's the problem to which the other answers allude, namely that changing any part of record hashed changes its table index. The unordered_set definition from the original question specifies "MeinHash", but we are not shown what it is, and if it factors in things that might be changed via an iterator, we're back to the problem described by the above answers. Typically though, not all the data in record is used to uniquely id an instance within a set. Let's say "name" is enough to disambiguate the student and gpa is just associated data that we may update. The constructor above strongly implies that, making the call to find above dangerous. It will create a temp, using the constructor, assign a name and a gpa of 2.0, and then look up the student using BOTH pieces of information. If "edgar" was added to the set with a gpa of 3.0, his record will never be found, let alone updated by the operation on the iterator (which won't even compile). The compiler takes into account the whole lifespan of an iterator when inferring which override of find to use, so if you use a naive hash function that includes all the fields of the struct, and the compiler sees you changing one of those fields, it "helps" you by failing at compile time. So the first thing you need to do is identify the fields that are truly intrinsic, and required for a hash, and which are not. Then you supply a hash function that uses only these fields - something like the following -
struct student_hash {
std::size_t operator()(const student& hashed_student) {
return std::hash<std::string>()(hashed_student.name);
}
};
For me (using clang), this was not quite enough - necessary, but not sufficient, but at least the compiler now knows that changing "gpa" will have no effect on the index of a record within hash table. I then had to use the mutable keyword with the declaration of "gpa" to explicitly say to the compiler that this field can change without changing what we writer considers the state of this data. Typically, it's used for refcounts or master pointers and other kinds of meta-data not intrinsic to the state of the struct instance, but it applies here as well. So now we have -
struct student {
std::string name;
mutable double gpa;
// indicates that a matching name means a hit
bool operator==(const student& other) const {
return name.compare(other.name) == 0;
}
student(const char* _name)
: name(_name)
, gpa(2.0) {}
};
std::unordered_set<student, student_hash> student_set;
auto found = student_set.find("edgar"); // will find "edgar" regardless of gpa
if (found != student_set.end()) {
found->gpa = 4.0; // <- no longer fails here. "found" is of type iterator
}
unordered_set is a kind of data structure where you cant modify an item without changing its location.
Non-const iterator is const here 'cause STL does protect you from such an obvious mistake.
If you want to modify an unordered_set's item you have to remove it and add it again.
You can cast const type to non-const type. By this you are 'telling the compiler' that you know what you are doing, so you should indeed know what you are doing.
We have got legacy code which returns huge sized lists of raw pointers to heap allocated objects (we can't use smart pointers), and we'll remove duplicates from the list and also delete them from heap.
For now, as it advised by gurus, I would like to try std::list::unique (or forward_list::unique) instead of algorithm std::unique.
I've read in http://en.cppreference.com/w/cpp/container/list/unique that within 'unique' predicate we shouldn't change objects, so is it safe by the term of standard to delete the “going to be removed” objects in list::unique?
And if so, what object in list::unique should be considered as a duplicate? In gnu implementation the 'b' will be removed, but in http://www.cplusplus.com/reference/list/list/unique/ is written that in pred(i, i-1), i item will be removed, so does this behaviour specified by standard ?
Is this (working in gcc) code correct in term of standard or is UB?
List.sort( [] (const Val *a, const Val *b) {
return *a < *b;
});
List.unique([] (const Val *a, const Val *b) {
if (*a == *b) {
delete b; // (1) working in gcc 4.6
// or (2) delete a (elsewhere)?
return true;
}
return false;
}) ;
Update #1
Mike's explanation was the most helpful one, but for now we're using such solution:
struct RawPtrEq {
bool operator()(const Val a, const Val b) { return *a == *b;}
};
auto it = adjacent_find( begin(List), end(List), RawPtrEq() );
while(it != end(li)) {
delete *it;
it = List.erase(it);
it = adjacent_find( it, end(List), RawPtrEq() );
}
No, there's no guarantee that this is well defined. unique is not specified completely enough to guarantee that this is the last time that b is passed to the predicate, so it's possible that the deleted pointer might be used again later.
I'm surprised that it works for you, since the specification is for b to be the first of the two elements, which is the one that would be kept if the either were removed.
I'd suggest storing either the objects themselves, or unique_ptr<Val> if you really need them to be dynamic, so that they are always destroyed automatically on removal. I've no idea why you say "we can't use smart pointers"; they would make much more sense than jumping through hoops to leave your legacy code unchanged.
For testing purposes I created a little unordered_set and tried to iterate over the set. The set holds an own class:
class Student {
private:
int matrNr;
string name;
public:
Student( const int& matrNr = 0, const string& name = "" )
: matrNr( matrNr ), name( name ) {}
void setNr( const int& matrNr ) {
this->matrNr = matrNr;
}
...
};
I inserted some elements and tried to change the objects during iteration:
unordered_set<Student, meinHash> meineHashTable;
meineHashTable.emplace( 12, "Fred" );
meineHashTable.emplace( 22, "Barney" );
meineHashTable.emplace( 33, "Wilma" );
for (int i = 0; i < meineHashTable.bucket_count(); i++) {
cout << "Bucketnummer: " << i << endl;
unordered_set<Student, meinHash>::local_iterator iter; // not constant?!?
if (meineHashTable.bucket_size( i ) > 0) {
for (iter = meineHashTable.begin( i ); iter != meineHashTable.end( i ); iter++) {
//const_cast<Student&>(*iter).setNr( 1234 ); //This does work
iter->setNr( 1234 ); //This does not work
}
}
else {
cout << "An empty Bucket" << endl;
}
}
I used a local_iterator (and not the const_local_iterator) but still I can't change the objects. For some reasons the iterator refers still to a constant object.
My question now: why is this so? If the normal iterator refers to a const object, what is the different between the const and the non-const iterator?
Tested with VisualStudio 2013 and minGW.
Thanks in advance for any help :-)
EDIT:
The Hash functor:
struct meinHash {
size_t operator()( const Student& s ) {
return s.getNr();
}
};
For finders of this topic in the future who have the same question, here is some example output if you change the matrNr with violent:
const_cast<Student&>(*iter).setNr( 5 );
and try to display it:
unordered_set<Student, meinHash>::local_iterator iter = meineHashTable.find( 5 );
iter->display();
you may get something like:
Bucketnummer: 0
An empty Bucket
Bucketnummer: 1
Matrikelnummer: 5
Name: Wilma
Bucketnummer: 2
An empty Bucket
Bucketnummer: 3
An empty Bucket
Bucketnummer: 4
Matrikelnummer: 5
Name: Fred
Bucketnummer: 5
An empty Bucket
Bucketnummer: 6
Matrikelnummer: 5
Name: Barney
Bucketnummer: 7
An empty Bucket
//The not wanted output ;-)
Matrikelnummer: -842150451
Name:
Both set and unordered_set have read-only keys. It's easy to see why this is the case - if the key value were to change, the data structure would have it filed in the wrong spot and you wouldn't be able to find it anymore.
Per your example, suppose your hash function simply returned the matrNr field. When the hash number changes, any lookup for 1234 will fail because there's nothing stored in that hash bucket.
It could be possible to change some part of the object that is not used in making the hash key, but that would lead to possible hard to track down bugs. The standards committee decided to eliminate that possibility by making the entire key const.
There are two ways around this restriction. The first is to split the key from the value and use a map or unordered_map instead. The second is to remove the item from the set and reinsert it after it's modified.
They value type of a set<K> is const K, and for a map<K, T> it is pair<const K, T>; ditto for the unordered versions.
An iterator gives you access to value_type &, and a const-iterator to a const value_type &. As you can see, neither iterator type can "undo" the constness of the key.
The reason the key is immutable is that it forms an integral part of the underlying data structure; changing the key would require a non-trivial internal rearrangement which would cause all sorts of problems (e.g. non-zero computational complexity (for element access!), and confused iterator ordering).
I had a similar problem and I was confused too. All the sources I looked at indicated that std::unordered_set::find can return a non-const iterator that dereferences to value_type&, which is non-const. On the other hand, all the above answers that state that changing field values within the instance changes its hash and therefore the way it is stored seem to make that impossible. It seems uncharacteristically "sloppy" for the spec to provide an interface that cannot be used, so there has to be a way to do something like what the questioner wants, and there is. You just have to give the compiler enough information to KNOW it's safe to provide you the non-const iterator. To further simplify the original question, we consider the following:
struct student {
std::string name;
double gpa;
// necessary for a decent member of a hash table. Compares all fields by default
bool operator==(const student& other) const = default;
student(const char* _name)
: name(_name)
, gpa(2.0) {}
};
std::unordered_set<student> student_set;
auto found = student_set.find("edgar"); // danger!! See note below
if (found != student_set.end()) {
found->gpa = 4.0; // <- compile failure here. "found" is of type const_iterator
}
If you just use the default std::hash<student>, it folds in all the data from the struct to create the hash - perhaps some combo of std::hash<std::string>(name) and std::hash<double>(gpa). Regardless of how it uses all this data, the compiler behaves as if it incorporates all the data and that's the problem to which the other answers allude, namely that changing any part of record hashed changes its table index. The unordered_set definition from the original question specifies "MeinHash", but we are not shown what it is, and if it factors in things that might be changed via an iterator, we're back to the problem described by the above answers. Typically though, not all the data in record is used to uniquely id an instance within a set. Let's say "name" is enough to disambiguate the student and gpa is just associated data that we may update. The constructor above strongly implies that, making the call to find above dangerous. It will create a temp, using the constructor, assign a name and a gpa of 2.0, and then look up the student using BOTH pieces of information. If "edgar" was added to the set with a gpa of 3.0, his record will never be found, let alone updated by the operation on the iterator (which won't even compile). The compiler takes into account the whole lifespan of an iterator when inferring which override of find to use, so if you use a naive hash function that includes all the fields of the struct, and the compiler sees you changing one of those fields, it "helps" you by failing at compile time. So the first thing you need to do is identify the fields that are truly intrinsic, and required for a hash, and which are not. Then you supply a hash function that uses only these fields - something like the following -
struct student_hash {
std::size_t operator()(const student& hashed_student) {
return std::hash<std::string>()(hashed_student.name);
}
};
For me (using clang), this was not quite enough - necessary, but not sufficient, but at least the compiler now knows that changing "gpa" will have no effect on the index of a record within hash table. I then had to use the mutable keyword with the declaration of "gpa" to explicitly say to the compiler that this field can change without changing what we writer considers the state of this data. Typically, it's used for refcounts or master pointers and other kinds of meta-data not intrinsic to the state of the struct instance, but it applies here as well. So now we have -
struct student {
std::string name;
mutable double gpa;
// indicates that a matching name means a hit
bool operator==(const student& other) const {
return name.compare(other.name) == 0;
}
student(const char* _name)
: name(_name)
, gpa(2.0) {}
};
std::unordered_set<student, student_hash> student_set;
auto found = student_set.find("edgar"); // will find "edgar" regardless of gpa
if (found != student_set.end()) {
found->gpa = 4.0; // <- no longer fails here. "found" is of type iterator
}
unordered_set is a kind of data structure where you cant modify an item without changing its location.
Non-const iterator is const here 'cause STL does protect you from such an obvious mistake.
If you want to modify an unordered_set's item you have to remove it and add it again.
You can cast const type to non-const type. By this you are 'telling the compiler' that you know what you are doing, so you should indeed know what you are doing.
I recently hit a problem and the only way I can see to avoid it is to use const_cast - but I'm guessing there is a way I'm not thinking of to avoid this without otherwise changing the function of the code. The code snippet below distills my problem into a very simple example.
struct Nu
{
Nu() {v = rand();}
int v;
};
struct G
{
~G()
{
for(auto it = _m.begin(); it != _m.end(); it++) delete it->first;
}
void AddNewNu()
{
_m[new Nu] = 0.5f;
}
void ModifyAllNu()
{
for(auto it = _m.begin(); it != _m.end(); it++) it->first->v++;
}
float F(const Nu *n) const
{
auto it = _m.find(n);
// maybe do other stuff with it
return it->second;
}
map<Nu*, float> _m;
};
Here, suppose Nu is actually a very large struct whose layout is already fixed by the need to match an external library (and thus the "float" can't simply be folded into Nu, and for various other reasons it can't be map<Nu, float>). The G struct has a map that it uses to hold all the Nu's it creates (and ultimately to delete them all on destruction). As written, the function F will not compile - it cannot cast (const Nu *n) to (Nu n) as expected by std::map. However, the map can't be switched to map<const Nu*, float> because some non-const functions still need to modify the Nu's inside _m. Of course, I could alternatively store all these Nu's in an additional std::vector and then switch the map type to be const - but this introduces a vector that should be entirely unnecessary. So the only alternative I've thought of at the moment is to use const_cast inside the F function (which should be a safe const_cast) and I'm wondering if this is avoidable.
After a bit more hunting this exact same problem has already been addressed here: Calling map::find with a const argument
This is because the map expects Nu* const, but you have given it a const Nu*. I also find it highly illogical and don't understand why, but this is how it is.
"find" in your case will return a const_iterator. putting:
map<Nu*,float>::const_iterator it = _m.find(n);
...
return it->second;
should work I think.
Since you are in a const method you can only read your map of course, not write/modify it