简体   繁体   English

在 C++ 集中找不到结构

[英]Can't find structs in a C++ set

I'm writing a set that contains some structs for a 3d graphics program.我正在编写一个包含 3d 图形程序的一些结构的集合。 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:这是一个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.因此,基本上,如果两个Objeto的模型指向相同的modelo地址,则它们是相同的。 That way, I can ditch the id member data from the Malla3D class.这样,我可以从Malla3D class 中删除id成员数据。 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() .我已经用 gdb 测试了operator ==并且它按预期工作,所以我不明白为什么find除了end()不能返回。 What am I doing wrong?我究竟做错了什么?

Your operators are comparing object pointers, not member values.您的操作员正在比较 object 指针,而不是成员值。 When you insert() an Objeto object into the std::set , a copy is stored.当您insert()一个Objeto object 到std::set时,将存储一个副本 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.当您稍后尝试find()一个Objeto object 时,您的operator<正在比较的this指针将不是您所期望的( std::set不使用operator==进行比较),因此为什么匹配没有找到。

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;
}

Demo演示

Or, if you really need to use Malla3D* pointers in Objeto (why?):或者,如果您真的需要在Objeto中使用Malla3D*指针(为什么?):

#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;
}

Demo演示

As molbdnilo said, I just need to use the operator < for the program to work correctly.正如 molbdnilo 所说,我只需要使用operator <即可使程序正常工作。

The solution: remove the operator == and rewrite the other to the following:解决方案:删除operator ==并将另一个重写为以下内容:

bool Objeto :: operator < (const Objeto & otro) const
{
    return modelo < otro.modelo;
}

This way, the memory addresses are ordered and can be matched with find .这样,memory 地址是有序的,可以与find匹配。 It's an unsatisfying solution to a very dumb problem, but I learnt a lot thanks to Remy.对于一个非常愚蠢的问题,这是一个不令人满意的解决方案,但感谢 Remy,我学到了很多东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM