I'm writing a set that contains some structs for a 3d graphics program. One of the things I'm trying to do is find if one of the structs is in a set to operate with that knowledge. Here's a mwe:
#include <iostream>
#include <set>
class Malla3D
{
public:
int id;
};
struct Objeto
{
Malla3D * modelo;
bool operator < (const Objeto & otro) const;
bool operator == (const Objeto & otro) const;
};
bool Objeto :: operator < (const Objeto & otro) const
{
return this < &otro;
}
bool Objeto :: operator == (const Objeto & otro) const
{
return modelo == otro.modelo;
}
int main ()
{
std::set<Objeto> objetos;
Malla3D * malla1 = new Malla3D({1});
Malla3D * malla2 = new Malla3D({2});
Malla3D * malla3 = new Malla3D({3});
Malla3D * malla4 = new Malla3D({4});
Objeto objeto1({malla1});
Objeto objeto2({malla2});
Objeto objeto3({malla3});
Objeto objeto4({malla4});
objetos.insert(objeto1);
objetos.insert(objeto2);
objetos.insert(objeto3);
objetos.insert(objeto4);
for (auto it = objetos.cbegin(); it != objetos.cend(); ++it)
std::cout << "Item in set: " << (*it).modelo->id << std::endl;
if (objetos.find(objeto1) != objetos.cend())
std::cout << "Found 1." << std::endl;
else
std::cout << "Couldn't find 1." << std::endl;
if (objetos.find(objeto2) != objetos.cend())
std::cout << "Found 2." << std::endl;
else
std::cout << "Couldn't find 2." << std::endl;
if (objetos.find(objeto3) != objetos.cend())
std::cout << "Found 3." << std::endl;
else
std::cout << "Couldn't find 3." << std::endl;
if (objetos.find(objeto4) != objetos.cend())
std::cout << "Found 4." << std::endl;
else
std::cout << "Couldn't find 4." << std::endl;
delete malla1;
delete malla2;
delete malla3;
delete malla4;
}
~
➜ g++ -g -Wall -Wextra -Wpedantic -std=c++17 mwe.cpp
~
➜ ./a.out
Item in set: 1
Item in set: 2
Item in set: 3
Item in set: 4
Couldn't find 1.
Couldn't find 2.
Couldn't find 3.
Couldn't find 4.
So, basically, two Objeto
s are the same if their modelo
s point to the same memory address. That way, I can ditch the id
member data from the Malla3D
class. I've tested the operator ==
with gdb and it works as intended, so I don't understand why find
can't return other than end()
. What am I doing wrong?
Your operators are comparing object pointers, not member values. When you insert()
an Objeto
object into the std::set
, a copy is stored. When you then try to find()
a Objeto
object later, the this
pointers that are being compared by your operator<
won't be what you are expecting ( std::set
does not use operator==
for comparisons), hence why matches are not found.
Try this instead:
#include <iostream>
#include <set>
struct Malla3D
{
int id;
bool operator < (const Malla3D & otro) const;
bool operator == (const Malla3D & otro) const;
};
bool Malla3D :: operator < (const Malla3D & otro) const
{
return id < otro.id;
}
bool Malla3D :: operator == (const Malla3D & otro) const
{
return id == otro.id;
}
struct Objeto
{
Malla3D modelo;
bool operator < (const Objeto & otro) const;
bool operator == (const Objeto & otro) const;
};
bool Objeto :: operator < (const Objeto & otro) const
{
return modelo < otro.modelo;
}
bool Objeto :: operator == (const Objeto & otro) const
{
return modelo == otro.modelo;
}
int main ()
{
std::set<Objeto> objetos;
Objeto objeto1{1};
Objeto objeto2{2};
Objeto objeto3{3};
Objeto objeto4{4};
objetos.insert(objeto1);
objetos.insert(objeto2);
objetos.insert(objeto3);
objetos.insert(objeto4);
for (auto it = objetos.cbegin(); it != objetos.cend(); ++it)
std::cout << "Item in set: " << it->modelo.id << std::endl;
if (objetos.find(objeto1) != objetos.cend())
std::cout << "Found 1." << std::endl;
else
std::cout << "Couldn't find 1." << std::endl;
if (objetos.find(objeto2) != objetos.cend())
std::cout << "Found 2." << std::endl;
else
std::cout << "Couldn't find 2." << std::endl;
if (objetos.find(objeto3) != objetos.cend())
std::cout << "Found 3." << std::endl;
else
std::cout << "Couldn't find 3." << std::endl;
if (objetos.find(objeto4) != objetos.cend())
std::cout << "Found 4." << std::endl;
else
std::cout << "Couldn't find 4." << std::endl;
}
Or, if you really need to use Malla3D*
pointers in Objeto
(why?):
#include <iostream>
#include <set>
struct Malla3D
{
int id;
bool operator < (const Malla3D & otro) const;
bool operator == (const Malla3D & otro) const;
};
bool Malla3D :: operator < (const Malla3D & otro) const
{
return id < otro.id;
}
bool Malla3D :: operator == (const Malla3D & otro) const
{
return id == otro.id;
}
struct Objeto
{
Malla3D* modelo;
bool operator < (const Objeto & otro) const;
bool operator == (const Objeto & otro) const;
};
bool Objeto :: operator < (const Objeto & otro) const
{
return *modelo < *(otro.modelo);
}
bool Objeto :: operator == (const Objeto & otro) const
{
return *modelo == *(otro.modelo);
}
int main ()
{
std::set<Objeto> objetos;
Malla3D * malla1 = new Malla3D{1};
Malla3D * malla2 = new Malla3D{2};
Malla3D * malla3 = new Malla3D{3};
Malla3D * malla4 = new Malla3D{4};
Objeto objeto1{malla1};
Objeto objeto2{malla2};
Objeto objeto3{malla3};
Objeto objeto4{malla4};
objetos.insert(objeto1);
objetos.insert(objeto2);
objetos.insert(objeto3);
objetos.insert(objeto4);
for (auto it = objetos.cbegin(); it != objetos.cend(); ++it)
std::cout << "Item in set: " << it->modelo->id << std::endl;
if (objetos.find(objeto1) != objetos.cend())
std::cout << "Found 1." << std::endl;
else
std::cout << "Couldn't find 1." << std::endl;
if (objetos.find(objeto2) != objetos.cend())
std::cout << "Found 2." << std::endl;
else
std::cout << "Couldn't find 2." << std::endl;
if (objetos.find(objeto3) != objetos.cend())
std::cout << "Found 3." << std::endl;
else
std::cout << "Couldn't find 3." << std::endl;
if (objetos.find(objeto4) != objetos.cend())
std::cout << "Found 4." << std::endl;
else
std::cout << "Couldn't find 4." << std::endl;
delete malla1;
delete malla2;
delete malla3;
delete malla4;
}
As molbdnilo said, I just need to use the operator <
for the program to work correctly.
The solution: remove the operator ==
and rewrite the other to the following:
bool Objeto :: operator < (const Objeto & otro) const
{
return modelo < otro.modelo;
}
This way, the memory addresses are ordered and can be matched with find
. It's an unsatisfying solution to a very dumb problem, but I learnt a lot thanks to Remy.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.