How to overload == operator to see if two objects with a string vector are equal? - c++

I am writing a class named StringSet which has vector<string> data and int length as its private members.
bool StringSet::operator == (StringSet d)
{
for (int i = 0; i < length; i++)
{
if (data[i] == d.data[i])
{
return true;
}
}
return false;
}
When I try calling this function like this,
StringSet doc1, doc2;
if (doc1 == doc2)
{
cout << "Both sentences are identical!\n";
}
I get an assertion failure saying vector subscript out of range, I know what that means but I don't know how it implies here. If anyone can point out an obvious mistake I have made that would be great as I am a newbie to c++.

It's simple
bool StringSet::operator == (const StringSet& d) const
{
return data == d.data;
}
std::vector and std::string have already comparison operators, therefore you don't have to implement something special.

Related

How to remove certain specified value from vectors?

mySongs is a vector that store a collection of songs input by the user. In the if statement, the program will check the elements in the vector with user input. If match, it will delete that specified value from the vector. When I look for the solution, I see someone recommend to use remove/erase idiom:. But when I implement in my code, it continue pop up this error C2678 binary '==': no operator found which takes a left - hand operand of type 'Song' (or there is no acceptable conversion)
void deleteSong() {
string songTitle;
cout << "\n\t\tPlease enter the particular song name to remove: ";
cin >> songTitle;
if (songTitle != "") {
for (Song songs : mySongs) {
if (songs.title == songTitle) {
mySongs.erase(find(mySongs.begin, mySongs.end, songs)); //erase an element with value
break;
}
}
}
}
This error is due to the fact that the class Song does not have an == operator. This can be solved in one of the two following ways
If you have access to the source code of Song then
add the following function to it. please note that const is necessary
bool operator == ( const Song& song)
{
//Do the comparison code here
}
If you don't have access to the source code. Then add the following function
bool operator == (const Song& song1, const Song& song2)
{
// Do the comparison code here
}
That said, there is another minor problem with your code
The erase function should be called like this
mySongs.erase(find(mySongs.begin(), mySongs.end(), songs));
I decided to add a minimal example to help you. In that example I assumed a certain implementation of Song, but that implementation does not have to be what you have
#include <iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
class Song
{
public:
std::string title;
/* bool operator ==(const Song& other)
{
return this->title == other.title;
}*/
};
bool operator ==(const Song& song1,const Song& other)
{
return song1.title == other.title;
}
std::vector<Song> mySongs={{"ali"},{"ahmed"},{"ali"}};;
void deleteSong() {
string songTitle;
cout << "\n\t\tPlease enter the particular song name to remove: ";
cin >> songTitle;
if (songTitle != "") {
for (const auto& songs : mySongs) {
if (songs.title == songTitle) {
mySongs.erase(find(mySongs.begin(), mySongs.end(), songs)); //erase an element with value
break;
}
}
}
}
int main() {
// your code goes here
return 0;
}

Sorting a Vector of a custom class with std::sort() causes a segmentation fault

I'd like to sort a vector of a custom class using std::sort() and overloading the < operator. Following the answer here: Sorting a vector of custom objects, I tried the following code:
class Evnt {
private:
int Day, Month;
string mydata;
public:
friend ifstream& operator >>(ifstream &in,Evnt &E){
char junk;
in >>junk>>E.Month>>junk>>E.Day;
getline(in,E.mydata);
return in;
}
bool operator<(const Evnt &E) const{
if(Month < E.Month)
return true;
else if(Day < E.Day)
return true;
return false;
}
};
int main(){
ifstream inpt("inputfile.txt")
Vector <Evnt> v;
Evnt tmpevnt;
while(intp>>tmpevnt)
v.push_back(tmpevent)
sort(v.begin(), v.end());
return 0;
}
The last line somewhat erratically causes segmentation faults. I followed the various examples fairly closely, and so am having issues figuring out what the problem is. It seems to only occur if I read a large number (~20+) items in.
std::sort requires a comparison operation that imposes Strict Weak Ordering.
That means that if a < b returns true, b < a must not return true.
Fix your comparison operator.
bool operator<(const Evnt &E) const{
if(Month < E.Month)
return true;
else if(Month == E.Month && Day < E.Day)
return true;
return false;
}
See this similar question for more information.

Segmentation Fault while comparing strings

In my program, there is a part where i need to sort an array of struct.
Everything goes nice until the end i think.
For some entries everything is nice and works until some entries at the end of the array.
There it throws a segmentation fault and i don't know why.
struct overview_table{
string o_timestamp;
string n_timestamp;
string dbID;
};
sort(overview.begin(),overview.end(),compareStrings);
static bool compareStrings(const overview_table &a_timestamp, const overview_table &b_timestamp){
cout << "744" << endl;
if ( a_timestamp.n_timestamp.compare(b_timestamp.n_timestamp) <= 0){
cout << "746" << endl;
return true;
} else {
cout << "749" << endl;
return false;
}
}
For information: the output was only to check where the segmentation fault is thrown. And it is between 744 and 746 and how i think at the end of the array. But i don't know why
If i'm not wrong, to sort 2 structs you have to compare the whole struct, not only a field. And you're comparing only the n_timestamp field. Second, you don't put <= in the comparison but just < or >.
This is an example of an operator overload:
bool operator<(const overview_table &a, const overview_table &b)
{
if ( a.n_timestamp.compare(b.n_timestamp) < 0) {return true;}
if ( a.n_timestamp.compare(b.n_timestamp) > 0) {return false;}
if ( a.o_timestamp.compare(b.o_timestamp) < 0) {return true;}
if ( a.o_timestamp.compare(b.o_timestamp) > 0) {return false;}
return a.dbID.compare(b.dbID);
}
hope this helps. Pleas ask if I was not clear!
The compare function shall satisfy the principle of weak ordering.
Change the function the following way
static bool compareStrings( const overview_table &a_timestamp,
const overview_table &b_timestamp )
{
return a_timestamp.n_timestamp < b_timestamp.n_timestamp;
}
A little more source would be nice...
But first of all: compare should return 0 in case of equality, so your
if ( a_timestamp.n_timestamp.compare(b_timestamp.n_timestamp) <= 0)
doesn't make any sense... Otherwise (if it's intended) your function's name is misleading.
To figure out, where your segmentation fault comes from, we need to see more sourcecode, but Segmentation faults indicate, that you are trying to acces nestet values from a null pointer, so in your case it seems, that one of your compared structs was never created...
Which could and should be checked by a if (null == x) return false; or something like that

Checking if Container has Value (c++)

I have a custom class 'team' and one of its attributes is its 'name.' After each 'team' is created, I add it to a vector teamList.
I would like to implement a function that continuously prompts the user for a team name which is not already taken by a team within the teamList. I have the following code:
while (true) {
string newString;
bool flag = true;
getline(cin, newString);
for (int i = 0; i < teamList.size(); i++) {
if (teamList[i].name.compare(newString) == 0) flag = false;
}
if (flag == true) {
return newString;
} else {
cout << "name already taken." << endl;
}
}
However, this code is really ugly; is there a better way to check? Also, a more general question- faced with an issue of ugly code (like this one), what kinds of steps can I take to find a new, cleaner implementation? Thanks.
I would use std::set, which deals with duplicates for you. As an example, you can see that the class is sorted by the string member, and when three are inserted in main, only two stay because two of the insertions have the same string, so they are treated equal.
#include <iostream>
#include <set>
#include <string>
struct SetThing {
SetThing(int value, const std::string &value2) : i(value), s(value2){}
int i;
std::string s;
bool operator<(const SetThing &other) const {
return s < other.s;
}
};
int main() {
std::set<SetThing> s;
s.insert(SetThing(5, "abc"));
s.insert(SetThing(4, "def"));
s.insert(SetThing(6, "abc"));
std::cout << s.size();
}
Now for inserting, you can just reprompt while the second member of the returned pair is false:
do {
//get input
} while (!teamList.insert(somethingBasedOnInput).second);
define an equality operator in team that can compare a team to a string:
bool team::operator==(string s) const
{
return(s==name);
}
Then you can use find:
vector<team>::const_iterator itr = find(teamList.begin(), teamList.end(),
newString);
if(itr!=league.end())
cout << "name already taken" << endl;

C++ vector problem

I'm getting some weird behavior with a vector in C++ I was hoping someone could help me out. I have a vector like so:
vector<Instruction*> allInstrs;
the struct for Instruction is as follows:
struct Instruction : simple_instr
{
InstrType type;
Instruction(const simple_instr& simple) : simple_instr(simple)
{
type = Simple;
loopHeader = false;
loopTail = false;
}
int Id;
bool loopHeader;
bool loopTail;
};
the problem I'm having is this:
I need to iterate through each instruction and pull out specific fields and use those to do some analysis on the instructions in the vector. To do that, I was basically doing
VariableList Variables;
void GenerateVariableList()
{
for (int i = 0; i < allInstrs.size(); i++)
{
Variables.Add(allInstrs[i]);
}
Variables.RemoveDuplicates();
}
Variable List is defined as
struct VariableList
{
void Add(simple_instr* instr)
{
PrintOpcode(instr);
switch(instr->opcode)
{
case STR_OP:
case MCPY_OP:
Add(instr->u.base.src1);
Add(instr->u.base.src2);
break;
case LDC_OP:
Add(instr->u.ldc.dst);
break;
case BTRUE_OP:
case BFALSE_OP:
Add(instr->u.bj.src);
break;
case CALL_OP:
cout << "CALL OP" <<endl;
break;
case MBR_OP:
Add(instr->u.mbr.src);
break;
case RET_OP:
if (instr->u.base.src1 != NO_REGISTER)
Add(instr->u.base.src1);
break;
case CVT_OP:
case CPY_OP:
case NEG_OP:
case NOT_OP:
case LOAD_OP:
Add(instr->u.base.dst);
Add(instr->u.base.src1);
break;
case LABEL_OP:
case JMP_OP:
break;
default:
Add(instr->u.base.dst);
Add(instr->u.base.src1);
Add(instr->u.base.src2);
break;
}
}
void Add(Variable var)
{
variableList.push_back(var);
}
void RemoveDuplicates()
{
if (variableList.size() > 0)
{
variableList.erase(unique(variableList.begin(), variableList.end()), variableList.end());
currentID = variableList.size();
}
}
VariableList()
{
currentID = 0;
}
VariableList(VariableList& varList, bool setLiveness = false, bool LiveVal = false)
{
currentID = 0;
for (int i = 0; i < varList.size(); i++)
{
Variable var(varList[i]);
if (setLiveness)
{
var.isLive = LiveVal;
}
variableList.push_back(var);
}
}
Variable& operator[] (int i)
{
return variableList[i];
}
int size()
{
return variableList.size();
}
vector<Variable>::iterator begin()
{
return variableList.begin();
}
vector<Variable>::iterator end()
{
return variableList.end();
}
protected:
int currentID;
vector<Variable> variableList;
void Add(simple_reg* reg, bool checkForDuplicates = false)
{ cout << "Register Check" <<endl;
if (reg == null)
{
cout << "null detected" << endl;
return;
}
if (reg->kind == PSEUDO_REG)
{
if (!checkForDuplicates || (checkForDuplicates && find(variableList.begin(), variableList.end(), reg->num) != variableList.end()))
{
cout << "Adding... Reg " << reg->num << endl;
Variable var(reg->num, currentID);
variableList.push_back(var);
currentID++;
}
}
}
};
When I do this though, every instruction goes to the default case statement, even though I knwo for a fact some instructions shouldn't. If I change GenerateVariableList to
void GenerateVariableList()
{
for (int i = 0; i < allInstrs.size(); i++)
{
PrintOpcode(allInstrs[i]);
Variables.Add(allInstrs[i]);
}
Variables.RemoveDuplicates();
}
so that there is now a second PrintOpCode in addition to the one in Variables.Add, the program behaves correctly. I can't understand why adding a second PrintOpcode makes it work correctly. All print Opcode is is a function with a switch statement that just prints out a specific string depending on what the value of one of simple_instr's fields is.
VariableList Variables is contained inside of a separate struct called CFG
If you need more information/code i can provide it. If the answer is obvious I apologize, I don't program in C++ very often
EDIT:
One of the answers left, deleted now though, got me the fix.
Previously I was doing
static vector<Instruction*> ConvertLinkedListToVector(simple_instr* instructionList)
{
vector<Instruction*> convertedInstructions;
int count = 0;
for (simple_instr* current = instructionList; current; count++, current = current->next)
{
//Instruction* inst = new Instruction(*current);
Instruction inst = Instruction(*current);
inst.Id = count;
convertedInstructions.push_back(&inst);
}
return convertedInstructions;
}
to make the vector, but after reading that answer I changed it back to using "new" and it works correctly now. Thanks for the help, sorry for the dumb question heh
Most likely the const simple_instr& simple passed to your constructor goes out of scope, and you keep an invalid reference/pointer to a simple_instr.
Possibly not related your problem, but certainly a potential source of strange behaviour: Your Instruction(const simple_instr& simple) constructor may be getting called when you don't intend it. Mark it explicit...
explicit Instruction(const simple_instr& simple) ...
If that causes compiler errors, then that's progress :-) You might need to write a copy constructor to make them go away, and explicitly call the old constructor where you need to.
So, there are several suspicious observations:
In your definition of VariableList you use a type called Variable - how is that type defined?
Iterating over a container should be done using an iterator:
for (vector<Intruction *>::iterator it = allInstrs.begin();
it != allInstrs.end();
++it) {
Variables.Add(*it);
}
You should consider using a vector of boost::shared_ptr, or a boost::ptr_vector instead of a vector of pointers.
I can give you a huge general overview of "don'ts" relating to your code.
You are right in this case to use classes "deriving" from simple_instr but you are doing it wrong, given that later on you do a switch statement based on type. A switch-statement based on type (rather than state) is an anti-pattern. You should be calling some virtual method of your base class.
You almost certainly do not want your derived class to copy from the base class. You want to construct it with the parameters to construct its base-class.
You want a vector of the base class pointers? And to manage lifetime probably shared_ptr
const-correctness. Some of your methods like size() should certainly be const. For others you might want two overloads.