views:

56

answers:

3
+1  Q: 

Duplicates in QSet

For a class X and a QSet< X* >, how is it possible to make sure that the QSet doesn't contain duplicate elements? The unique property in each object of type X is a QString that can be fetched using getName().

I've implemented the qHash(X*) function, the operator==(), operator<() and operator>(), but the QSet still accepts duplicate elements, i.e., those with the same Name.

Could someone help me out in making this work?


Ok. Here's what I'm trying to do. I have a class Y and a class X, both of which inherit QDialog. A function in class Y ( a slot), is responsible for spawning objects of class X. The dialog for Y is to be made responsible for the X objects spawned. This is why I created a QSet< X* > member in Y.

+1  A: 

The problem is that you cannot overload operator== like this:

bool operator==(X*, X*);

This is because at least one of the argument must be of class type.

Since you say you implemented operator==, I suppose you did something like this:

struct X
{
    bool operator==(X*) const;
};

This operator will never be called when QSet tries to fiend duplicates because it needs a left argument of type X and a right of type X*

I can see two possible solutions to this problem:

  • Do not store your items as pointers (ie using QSet<X>). This will allow you to overload the correct operators. This solution, however, is not always feasible.
  • If you could enforce somehow that there is only one object with a given id, you could just store pointers in you QSet without needing to overload any operators nor the qHash function.

Edit: If your design allows to create multiple X-objects with the same id but you only want one such object to exist at any time, maybe it's best to use a QMap which maps from id to X*. When you create a new object, do something like this:

QString newId = ...;
delete objectsMap[newId];
objectsMap[newId] = new X(newId);

Job
Any idea regarding the implementation of QSet<>::contains() ?? I mean how does it check if the requested item is in the set?
Saurabh Manchanda
In your case (using `QSet<X*>`), it will first calculate the hash value (using `qHash(X*)`). Then it will compare all entries having this hash value using the language defined `bool operator==(const X*, const X*)`.
Job
I have tried debugging it, but none of the functions get called. Why does that happen? I'm going bananas !!
Saurabh Manchanda
Job
I don't know how, but now the qHash is being called, but still as the operator==() is not being called, I'm helpless!! :( :(
Saurabh Manchanda
`struct Foo{bool operator==(const Foo}}; QSet<Foo> set; set << Foo(); set.contains(Foo());` In this example, the operator will definitely get called.
Job
@Job: I have edited the question. Please check it. You might be able to help me better.
Saurabh Manchanda
Regarding the edited post:Looks like that's the only feasible solution in this case.
Saurabh Manchanda
A: 

Depending on your exact requirements, you could use a sorted vector together with std::unique (which accepts a custom binary predicate for comparison).

Frank
This would be my last choice. It would be good if I could get the QSet<>::contains() function to work.
Saurabh Manchanda
A: 

Could you use QMap instead? Your dialog would have member variable QMap<QString, X*> items. Then the checking and creating new X's would be like:

QString name = "foo";
if (!items.contains(name))
{
    items[name] = new X(name);
}
else
{
    // "foo" already exists
}

Maybe this is not as elegant solution as using QSet might be, but I think this is shorter and easier to understand.

Roku
Yes, I just implemented that only!
Saurabh Manchanda