logical comparison operator - c++

Here is my code for my logical comparison operator (==) overloaded. I use this to check if two strings are identical in size and content. It should return false otherwise.
bool MyString::operator==(const MyString& other)const
{
if(other.Size == this->Size)
{
for(int i = 0; i < this->Size+1; i++)
{
if(&other == this)
return true;
}
}
else
return false;
}
When I ran valgrind it told me warning control reaches end of non-void function. Any suggestions on how to fix this issue and what I could do to better the code?

When control reaches the end of your for loop, you immediately get to the end of the function without returning a value.
It looks to me like you have the logic in your for loop munged anyway -- it's comparing the address of the other item to this. While it's sort of okay to do that, you only need to do it once, not in a loop.
In the loop, you undoubtedly want to compare the characters in the string, not the addresses of the objects.
Edit:
A typical implementation would be something on this general order:
class MyString {
char *data;
size_t length;
public:
// ...
bool operator==(MyString const &other) const {
if (length != other.length)
return false;
for (int i=0; i<length; i++)
if (data[i] != other.data[i]) // If we see any inequality
return false; // they're not equal
return true; // all equal, so the strings are equal.
}
};

It's not too clear what determines equality if the sizes are equal, but
the loop suggests that you're looking for something like:
bool
MyString::operator==( MyString const& other ) const
{
return size == other.size && std::equals( ??? );
}

Well, first of all, if you enter the for loop, and the condition &other == this will not be met, you will never return anything. To fix this, you should just remove the else statement. This will cause your function to return false either if the other.Size == this->Size condition is not met, or if you've gone through the whole loop, and have not used return inside of it.
The second problem is the line if(&other == this). I believe that inside of the loop you intend to check all the symbols of the strings. But now you are only checking the pointer to the class itself. To check the characters, you will need to use something like if( other->data == this->data ), provided you have a data member in which you store the...data (sorry for tautology).
Another little flow is in the design. You see, to check that the strings are equal, you need to look through each and every character and check that they match. However, to prove the strings are not equal, you need to find just 1 pair of characters that does not match. After that, it is pointless to continue comparing. So it is better to changee your condition in the cycle to a negative one, in order to stop comparing immediately after you fuond a pair that does not match, and not to do useless comparations of other characters.
Generaly, it is a good practice to return all the errors as fast as it's possible and avoid unneeded cumputation. So if you can check something in the begining of your function with a simple check, better do it.
So, after all, you should have something like this:
bool MyString::operator==(const MyString& other)const
{
if(other.Size != this->Size)
return false;//If the sizes do not match, no need to check anything else. Just return false.
//If we are here, the sizes match. Lets check the characters.
for(int i = 0; i < this->Size+1; i++)
{
//If some pair doesnt match, the strings are not equal, and we exit.
if( other->data[i] != this->data[i])
return false;
}
//If we are here, all the characters did match, so we return true.
return true;
}

Just get rid of the else. This way there is a "default" behaviour returning false if the condition is not met. It's the functionality you intend, and the compiler or syntax checker won't complain.

Related

Cannot dereference double pointer, " no match for operator* "

I'm trying to search through an array of pointers to objects of class Shape. I have written the following code. However, I'm getting this error: "no match for operator*", and I don't know where to go from here. Any help is appreciated.
Shape** shapesArray;
bool doesNameExist(string name) {
for (int i = 0; i < shapeCount; i++)
{
if(*(shapesArray[i])->getName() == name)
{
return true;
}
else
{
return false;
}
}
}
shapesArray is a Shape**
shapesArray[i] is Shape*
(shapesArray[i])->getName() is dereferencing shapesArray[i] and calls its
member getName
So far nothing wrong. I guess this is what you actually want to get, but you add another *:
*(shapesArray[i])->getName() tries to dereference what was returned from getName (a std::string perhaps?)
PS: You return from the loop in the first iteration in either case. If you want to search in the array you need to loop until you find it (then return true) or loop till the end (then return false after the loop, because it wasn't found).

What is the most efficient way to return results from recursion?

There are 2 possible ways that I am familiar with while returning a boolean/integer value from a recursive function that defines is the operation carried out was a success or not.
Using static variables inside the recursive function. Changing values in the recursive calls and then returning the final value once everything is done.
Passing the result variable by reference to the recursive function and then manipulating its values in the function and then checking if the value corresponds to the result or not.
void Graph::findPath(string from, string to)
{
int result = 0;
if (from == to) cout<<"There is a path!"<<endl;
else
{
findPathHelper(from, to, result);
if (result) cout<<"There is a path!"<<endl;
else cout<<"There is not a path!"<<endl;
}
}
void Graph::findPathHelper(string from, string toFind, int &found)
{
for (vector<string>::iterator i = adjList[from].begin(); i != adjList[from].end(); ++i)
{
if (!(toFind).compare(*i))
{
found = 1;
break;
}
else
findPathHelper(*i, toFind, found);
}
}
Is there a better way to achieve this?
Thank You
I have changed your implementation to use a return value
bool Graph::findPathHelper(const string& from, const string& toFind)
{
for (vector<string>::iterator i = adjList[from].begin(); i != adjList[from].end(); ++i)
{
// I have assumed you comparison was incorrect - i.e. toFind == *i is that you want
// toFind == *i - The two strings are equal - Thus found
// or
// Recurse on *i - Have we found it from recursion
if (toFind == *i || findPathHelper(*i, toFind)) {
return true;
}
}
// We have searched everywhere in the recursion and exhausted the list
// and still have not found it - so return false
return false;
}
You can return a value in the recursive function and use that returned value for checking if it was success or not in subsequent calls.
Using static variable for this purpose may work but it's generally not a good IDEA and many consider it as bad practice.
Look into the below link which explains why we must avoid static or global variables and what kind of problems it could lead to during recursion.
http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/recursion2.html
Note: I do not have enough reputation still to make a comment; and therefore i have posted this as answer.

bool method inside a class ''Control may reach end o non-void function''

So, i have a class called Vuelo, it has a method in which i can add a passenger to an airplane flight, i must check that the passenger id is not already in the array (the array is at first with all zeros), i must also check that there is enough space for another passenger to be added (max 10)
bool Vuelo :: agregarPasajero(int id)
{
int i = 0;
for(int iC = 0; iC < 10; iC++)
{
if (listaPasajeros[iC] == id)
{
i++;
return false;
}
}
if(i == 0)
{
if(cantidadPasajeros >= 10)
{
return false;
}
else
{
return true;
cantidadPasajeros++;
}
}
}
If i is not zero, you get to the end of the function without any kind of return statement. Since you declared the function to always return a bool, you should provide one for that case.
Now, you may know that i will never be zero at that spot, but the logic for that is fairly complex (I missed it on the first reading), and a compiler cannot be expected to realize that there is in fact no chance of control flow ever getting to the end of the function without encountering a return. In this case it's best to add a dummy return.
You can probably get away with not having a dummy return if you remove the bogus i == 0 test. i will necessarily always be zero at that point, since if it were ever increased, the function immediately returns false.
The statement cantidadPasajeros++; will never be executed since it is located after a return statement. Any halfway decent compiler also warns on that.

Overloaded Operator < to compare strings, sort linked list using string.compare?

If anything in this code looks weird (like the illogical use of pointers) it's because it's for an assignment, so no need to let me know that there's absolutely no reason to use pointers in this situation. Thank you for you help in advance.
The code works for me except one thing, the insertNode function uses an overloaded < from the Pet class. this operator is supposed to compare the strings using the string.compare() function and return true or false based on the resulting value. However no sorting is done at all and the input file is just read in normally from beginning to end.
The problem is in the snippet below
bool Pet::operator <(Pet &right)
{
if (name.compare(right.name) < 0)
return true;
else if (name.compare(right.name) > 0)
return false;
}
It seems to me that there is nothing wrong with this that would cause nothing to be changed. I haven't been able to test if the operators are right (> 0 and < 0) but i'm more concerned that it is doing nothing at all.
Your comparison function doesn't handle the case when the strings are equal.
bool Pet::operator <(Pet &right)
{
if (name.compare(right.name) < 0)
return true;
else if (name.compare(right.name) > 0)
return false;
}
string.compare returns a negative value if it's less then it's argument, 0 when they are equal and a positive value when it's bigger. You don't handle the case when it returns 0 and it therefore falls off the end of the function which is undefined behavior.
Change the else if to:
else if (name.compare(right.name) >= 0)
#Benjamin is right, your whole function could be shortened down to:
bool Pet::operator <(Pet &right)
{
return name.compare(right.name) < 0
}
I somehow always oversee these things when answering questions...

A bool function doesn't work in stable_sort function

The shipwreck;
Input a number, than a vector of type Passenger passengers(number), where Passenger is a struct that consists of string name and string status;
the problem is to sort the passengers who was on the ship by the next priority:
a) first who leaves the ship is rat, than the ship leaves whoman or a child, than the ship leaves a man, the last one who leaves the ship is the captain;
b) it is necessary to write a bool function which we will use in function stable_sort to sort the vector of passengers;
I tried this:
int Priority1(Passenger pas)
{
if(pas.status == "rat")
return 3;
if(pas.status == "woman" || pas.status == "child")
return 2;
if(pas.status == "man")
return 1;
if(pas.status == "captain")
return 0;
}
bool Priority(Passenger pas1, Passenger pas2)
{
return Priority1(pas1) > Priority1(pas2);
}
If your trying to implement an ordering function for one of the
standard library functions, your function is trivially wrong,
because it returns true if both passengers are rats. To
establish a proper ordering function, comparing any two entries
in the same equivalence class must return false.
Further down... what happens if both passengers are men? None
of your if are true, and you fall off the end, resulting in
undefined behavior. (FWIW: it's generally a bad practice to
throw return around right and left in the function. One
single return, as the last line in the function, and outside of
any control structure is a good general rule.)
Anyway, the approach I would take would be to to map both values
to an integral priority, and then return Priority(pas1) < Priority(pas2);. Much simpler, and guaranteed not to miss
any cases.
if(pas1.status == "man" && pas2.status != "woman" && pas2.status == "child" && pas2.status != "rat")
I think the third condition pas2.status == "child", should be pas2.status != "child"
Also, there is no default return statement in the function.