QMap contains return always true - c++

I have this code for the class IdTask
class IdTask
{
public:
IdTask(QString host, QString id) : _host(host), _id(id) {}
IdTask(const IdTask & idT) : _host(idT._host), _id(idT._id) {}
QString host() const { return _host;}
QString id() const { return _id;}
inline bool operator ==(const IdTask& idT) const { return _host == idT.host() && _id == idT.id();}
inline bool operator <(const IdTask& idT) const { return _host < idT.host() && _id < idT.id();}
private:
QString _host;
QString _id;
};
And the class IdResult
class IdResult
{
public:
IdResult(IdTask idT, QString id) : _idTask(idT), _id(id) {}
IdTask idTask() const { return _idTask;}
QString id() const { return _id;}
bool operator < (const IdResult& idR) const { return _idTask < idR.idTask() && _id < idR.id();}
private:
IdTask _idTask;
QString _id;
};
I create a QMap like this :
QMap<IdResult, QString> mapIdResultInput;
mapIdResultInput.insert(IdResult(IdTask("localhost", "init"), "a"), "_a");
The problem is with the function contains.
mapIdResultInput.contains(IdResult(IdTask("b", "c"), "g"));
It return always true.
What is the problem with my code?

I would solve this in the following way: I would sort my IdResults first by IdTask and than, if IdTasks are equal, by id. Here is my implementation of your operators in the classes:
class IdTask
{
public:
[..]
bool operator ==(const IdTask& idT) const
{ return _host == idT.host() && _id == idT.id(); }
bool operator <(const IdTask& idT) const
{ return (_host < idT.host()) || (_host == idT.host() && _id < idT.id()); }
[..]
};
And
class IdResult
{
[..]
bool operator < (const IdResult& idR) const
{ return (_idTask < idR.idTask()) || (_idTask == idR.idTask() && _id < idR.id()); }
[..]
};
And the test
QMap<IdResult, QString> mapIdResultInput;
mapIdResultInput.insert(IdResult(IdTask("localhost", "init"), "a"), "_a");
bool b = mapIdResultInput.contains(IdResult(IdTask("b", "c"), "g")); // false
b = mapIdResultInput.contains(IdResult(IdTask("localhost", "init"), "a")); // true

Related

How does inheritance works in case of factory methods in cpp?

I'm trying to solve this simple riddle at codingames and I thought i will exercise in OOP
However, it seems I've forgotten how CPP works in this field and I got an error I do not comprehend.
/tmp/Answer.cpp:82:1: error: invalid abstract return type ‘Sign’
82 | Sign from_str(const int value, const std::string& s)
| ^~~~
/tmp/Answer.cpp:14:7: note: because the following virtual functions are pure within ‘Sign’:
14 | class Sign {
| ^~~~
/tmp/Answer.cpp:22:25: note: ‘virtual std::string Sign::str() const’
22 | virtual std::string str() const = 0;
| ^~~
/tmp/Answer.cpp:82:6: error: invalid abstract return type for function ‘Sign from_str(int, const string&)’
82 | Sign from_str(const int value, const std::string& s)
| ^~~~~~~~
/tmp/Answer.cpp: In function ‘Sign from_str(int, const string&)’:
/tmp/Answer.cpp:85:26: error: cannot allocate an object of abstract type ‘Sign’
85 | return Rock(value);
| ^
/tmp/Answer.cpp:87:27: error: cannot allocate an object of abstract type ‘Sign’
87 | return Paper(value);
| ^
/tmp/Answer.cpp:89:30: error: cannot allocate an object of abstract type ‘Sign’
89 | return Scissors(value);
| ^
/tmp/Answer.cpp:91:28: error: cannot allocate an object of abstract type ‘Sign’
91 | return Lizard(value);
| ^
/tmp/Answer.cpp:93:27: error: cannot allocate an object of abstract type ‘Sign’
93 | return Spock(value);
And the code looks like this:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Rock;
class Paper;
class Scissors;
class Sign {
public:
Sign(const int v): value(v) {};
virtual ~Sign() {};
bool operator<(const Sign& other) { return value < other.value ? false : true; }
virtual std::string str() const = 0;
int value{};
};
class Rock : public Sign {
public:
Rock(const int v): Sign(v) {};
bool operator<(const Paper& other) { return true; }
bool operator<(const Scissors& other) { return false; }
std::string str() const override { return "Rock"; }
};
class Paper : public Sign {
public:
Paper(const int v): Sign(v) {};
bool operator<(const Rock& other) { return true; }
bool operator<(const Scissors& other) { return false; }
std::string str() const override { return "Paper"; }
};
class Scissors : public Sign {
public:
Scissors(const int v): Sign(v) {};
bool operator<(const Rock& other) { return false; }
bool operator<(const Paper& other) { return true; }
std::string str() const override { return "Scissors"; }
};
Sign from_str(const int value, const std::string& s)
{
if(s == "R")
return Rock(value);
if(s == "P")
return Paper(value);
if(s == "C")
return Scissors(value);
throw 1;
}
int main()
{
int N;
cin >> N; cin.ignore();
std::vector<Sign> s{};
for (int i = 0; i < N; i++) {
int NUMPLAYER;
string SIGNPLAYER;
cin >> NUMPLAYER >> SIGNPLAYER; cin.ignore();
s.emplace_back(from_str(NUMPLAYER, SIGNPLAYER));
}
}
At this point, I don't really understand why I can't use Sign as the return value from the factory method that is returning concrete types and emplace it on my data pile.
And if I add to the base class
virtual std::string str() const { return "Sign"; };
I will only get the base class printout.
You are sufferring from object slicing, both in your return type from from_str and in your vector <Sign>.
Like it or not, you are going to have to use pointers, but if you use smart pointers then the pain will go away. So, first change your from_str function like so:
std::unique_ptr <Sign> from_str(const int value, const std::string& s)
{
if(s == "R")
return std::make_unique <Rock> (value);
if(s == "P")
return std::make_unique <Paper> (value);
if(s == "C")
return std::make_unique <Scissors> (value);
throw 1;
}
And then change your vector to:
std::vector<std::unique_ptr <Sign>> s{};
And that's all you need to change. The fact that you're using std::unique_ptr takes care of any memory management issues.
Without allocation, you might use std::variant:
struct Rock
{
std::string str() const { return "Rock"; }
};
struct Paper
{
std::string str() const { return "Paper"; }
};
struct Scissors
{
std::string str() const { return "Scissors"; }
};
using Sign = std::variant<Rock, Paper, Scissors>;
bool winSigns (Paper, Rock) { return true; }
bool winSigns (Rock, Scissors) { return true; }
bool winSigns (Scissors, Paper) { return true; }
template <typename Sign1, typename Sign2>
bool winSigns (Sign1, Sign2) { return false; }
Sign from_str(const std::string& s)
{
if (s == "R")
return Rock{};
if (s == "P")
return Paper{};
if (s == "C")
return Scissors{};
throw 1;
}
int main()
{
std::string SIGNPLAYER1;
std::cin >> SIGNPLAYER1;
Sign sign1 = from_str(SIGNPLAYER1);
std::string SIGNPLAYER2;
std::cin >> SIGNPLAYER2;
Sign sign2 = from_str(SIGNPLAYER2);
std::visit([](auto lhs, auto rhs){
std::cout << lhs.str() << "versus" << rhs.str() << std::endl;
if (winSigns (lhs, rhs)) std::cout << "player1 wins\n";
else if (winSigns (rhs, lhs)) std::cout << "player2 wins\n";
else std::cout << "Draw\n";
}, sign1, sign2);
}
Demo

I'm not able to delete elements of these vectors

I want to delete every element at a certain index (that corresponds to a certain content), but I'm getting a segmentation fault... This is the structure of my code and the method deleteRecord is what I've tried but doesn't work:
class Tab {
public:
Tab();
~Tab() {};
bool colIsPresent(const string & col_name);
template <typename S> void deleteRecord(S & content, const string & col_name) {
int delete_pos;
if (!this->colIsPresent(col_name)) return;
const auto & it_columns = _columns.find(col_name);
if (it_columns != _columns.end()) {
auto ci = dynamic_cast<ColumnImpl<S> *>(it_columns->second.get());
if (ci != nullptr) {
for (int i = 0; i < ci->getData().size(); i++) {
if (ci->getData()[i] == content) {
delete_pos = i;
}
for (auto & it_columns_2 : _columns) {
auto ci2 = dynamic_cast<ColumnImpl<S> *>(it_columns_2.second.get());
ci2->getData().erase(ci2->getData().begin() + delete_pos);
}
}
}
}
}
private:
map<string, shared_ptr<Column>> _columns;
};
template <typename T> class ColumnImpl : public Column {
public:
ColumnImpl() : Column() {}
ColumnImpl(const T& to_set);
vector<T> & getData() { return _data; }
protected:
vector<T> _data;
};
class Column {
public:
Column();
virtual ~Column() {};
virtual string getType() = 0;
};
class Database {
public:
Database();
~Database();
bool tabIsPresent(const string & tab_name);
template <typename S> void deleteRecordFromTab(const string & tab_name, S & content, const string & col_name) {
const auto & it_target_tab = _tables.find(tab_name);
it_target_tab->second.deleteRecord(content, col_name);
}
private:
map<string, Tab> _tables;
};
Reproducible example:
Database data_base;
string tab = "EX_TAB", str1 = "STR_EX1", str2 = "STR_EX2", age = "AGE", name = "NAME", integer = "INT", text = "TEXT";
int a = 17, b = 18;
data_base.createNewTable(tab);
data_base.addColumnToTab(tab, age, integer);
data_base.addColumnToTab(tab, name, text);
data_base.addElemToColOfTab(tab, age, a);
data_base.addElemToColOfTab(tab, age, b);
data_base.addElemToColOfTab(tab, name, str1);
data_base.addElemToColOfTab(tab, name, str2);
data_base.deleteRecordFromTab(tab, str1, name);
// createNewTable creates a new table
// addColumnToTab adds a new column of the right type to _columns
// addElemToColumnOfTab adds an element to the targeted column

How to inherit methods that return a reference to the current object?

There is a base class
class LineEditItem
{
public:
LineEditItem(QLineEdit* le, const Values_t& values = Values_t()):
values(values),
le(le)
{}
LineEditItem &addValue(int v, const QString &s)
{
values[v] = s;
return *this;
}
LineEditItem &addValues(const Values_t& vals)
{
for (auto key: vals.keys())
{
values[key] = vals[key];
}
return *this;
}
void setValue(uint32_t v)
{
QString str;
if (values.contains(v))
{
str = values[v];
}
else
{
str = "";
}
le->setText(str);
}
void clearValue()
{
le->clear();
}
protected:
Values_t values;
QLineEdit* le;
};
There is a child class that must inherit the addValue and addValues methods
class LineEditItemBits: public LineEditItem
{
public:
LineEditItemBits(QLineEdit* le, int begin, int end, const Values_t& values = Values_t()):
LineEditItem(le, values),
begin(begin),
end(end)
{}
void setValue(uint32_t v)
{
int s = end - begin + 1;
v = (v >> begin) & ((1 << s) - 1);
LineEditItem::setValue(v);
}
LineEditItemBits &addValue(int v, const QString &s)
{
LineEditItem::addValue(v, s);
return *this;
}
LineEditItemBits &addValues(const Values_t& vals)
{
LineEditItem::addValues(vals);
return *this;
}
private:
int begin;
int end;
};
But you have to explicitly prescribe these methods and call base class methods from them.
How to inherit these methods from the base class so that they return a reference to the child class?
From my understanding you are trying to override these functions, so you should make them virtual in parent class.

segfault accessing qlist element through an iterator

I get a segfault while iterating over a QList. I don't understand what I am doing wrong.
I have a QList of Conversation. Inside a Conversation I have a QList of Msg. Below are the class description :
Msg class :
class Msg {
public:
Msg();
Msg(const Msg& other);
Msg& operator=(const Msg& other);
virtual ~Msg();
bool operator==(const Msg& other);
QString id() const { return _id; }
MsgContact author() const { return _author; }
MsgContact dest() const { return _dest; }
QDateTime date() const { return _receivedDate; }
MsgDirection direction() const { return _direction; }
QString text() const { return _text; }
bool transmitted() const { return _transmitted; }
void setId(const QString& id) { _id = id; }
void setAuthor(const MsgContact& author) { _author = author; }
void setDest(const MsgContact& dest) { _dest = dest; }
void setDate(const QDateTime& receivedDate) { _receivedDate = receivedDate; }
void setDirection(const MsgDirection& direction) { _direction = direction; }
void setText(const QString& text) { _text = text; }
void setTransmitted(const bool& transmitted) { _transmitted = transmitted; }
private:
QString _id;
MsgContact _author;
MsgContact _dest;
QDateTime _receivedDate;
MsgDirection _direction;
QString _text;
bool _transmitted; //indique que le message a été transmis
bool _read; //indique la lecture
};
Conversation class :
class Conversation
{
public:
Conversation();
Conversation(const Conversation& other);
virtual ~Conversation();
Conversation& operator=(const Conversation& other);
bool operator==(const Conversation& other);
bool isNull() const { return (NULL == _title || NULL == _destId); }
const QString title() const { return _title; }
const QString destId() const { return _destId; }
QList<Msg> messages() const { return _messages; }
void setDestId(const QString& destId) { _destId = destId; }
void setTitle(const QString& title) { _title = title; }
void addMsg(const Msg& msg);
static Conversation INVALID_CONVERSATION;
private:
QList<Msg> _messages;
QString _title;
QString _destId;
};
void Conversation::addMsg(const Msg& msg)
{
_messages.append(msg);
}
Code that generate the segfault. I create a message, I iterate over the Conversation list to add the message in the related conversation. Then, i want to iterate over the message list and I get a segfault. I use different way to access to the message which works fine.
Msg *m = new Msg();
m->setId(xmppMsg.id());
m->setDest(findContactById(conversationId));
m->setDirection(MsgOutgoing);
m->setAuthor(_myContact);
m->setText(message);
m->setDate(xmppMsg.stamp());
QList<Conversation>::iterator it;
for(it = _conversations.begin(); _conversations.end() != it; it++)
{
if((*it).destId() == conversationId)
{
(*it).addMsg(*m);
Q_EMIT(conversationChanged((*it)));
break;
}
}
qDebug() << "NB : " <<(*it).messages().size(); // ok, the number of message is incremented.
//test several way of accessing a message, these works fine.
qDebug() << "doSend " << it->messages().at(0).id();
qDebug() << "doSend " << it->messages().begin()->id();
qDebug() << "doSend " << (*(it->messages().begin())).id();
//try to iterate
QList<Msg>::iterator msgIt = it->messages().begin();
if(msgIt != it->messages().end())
{
qDebug() << "TEST - "<< msgIt->id(); //segfault.
}
Thank you for your help
(Edited away first "answer", this is an actual attempt at an answer)
My guess:
QList<Msg> messages() const { return _messages; }
It's returning a copy of the QList _messages, rather than a reference to it. I'm not sure that it would give the results you're seeing, but it looks wrong to me. Maybe try something like this?
QList<Msg>& messages() const { return _messages; }

Fix QString size (length)

For some reason I need to use string with fixed size. Now I'm looking on a QString class.
But there I have some questions with making QString object having constant size.
For example, I want to have string with size 10, it means, that if I would try to write some string with more than 100 chars in it, it would cut all the characters after 100 one.
I found constructor for QString in Qt docs, but I'm not sure if it would work as I told
QString( int size , QChar ch)
What can you suggest in such situation?
You can have a wrapper class that has a string, but is not a string, yet it can be used wherever a QString could be used. It can also be used with all QString's methods and operators, as long as you treat it like it were a pointer.
#include <QString>
class FixedWidthString {
mutable QString m_string;
//! Ignored if negative.
int m_maxLength;
inline const QString& data() const {
if (m_maxLength >= 0 && m_string.length() > m_maxLength)
m_string.truncate(m_maxLength);
return m_string;
}
inline QString& data() {
if (m_maxLength >= 0 && m_string.length() > m_maxLength)
m_string.truncate(m_maxLength);
return m_string;
}
public:
explicit FixedWidthString(int maxLength = -1) : m_maxLength(maxLength) {}
explicit FixedWidthString(const QString & str, int maxLength = -1) : m_string(str), m_maxLength(maxLength) {}
operator const QString&() const { return data(); }
operator QString&() { return data(); }
QString* operator->() { return &data(); }
const QString* operator->() const { return &data(); }
QString& operator*() { return data(); }
const QString& operator*() const { return data(); }
FixedWidthString & operator=(const FixedWidthString& other) {
m_string = *other;
return *this;
}
};
int main() {
FixedWidthString fs(3);
FixedWidthString fs2(2);
*fs = "FooBarBaz";
Q_ASSERT(*fs == "Foo");
fs->truncate(2);
Q_ASSERT(*fs == "Fo");
fs->append("Roo");
Q_ASSERT(*fs == "FoR");
fs->truncate(1);
*fs += "abc";
Q_ASSERT(*fs == "Fab");
fs2 = fs;
Q_ASSERT(*fs2 == "Fa");
}