problem with `==` operator - c++

There is some class wComplex with == operator.
#ifndef WCOMPLEX_H
#define WCOMPLEX_H
#include <stdio.h>
// sample class of complex-like numbers with weird `==` operator
class wComplex{
private:
double realPart;
double imagePart;
public:
wComplex();
wComplex(double R);
wComplex(double R, double I);
bool operator==(wComplex &);
void print();
};
wComplex::wComplex(){
realPart = 0;
imagePart = 0;
}
wComplex::wComplex(double R){
realPart = R;
imagePart = 0;
}
wComplex::wComplex(double R, double I)
{
realPart = R;
imagePart = I;
}
bool wComplex::operator==(wComplex &El){
double diff = realPart*realPart + imagePart*imagePart -
El.realPart*El.realPart - El.imagePart*El.imagePart;
return (diff == 0);
}
void wComplex::print(){
printf("(%g) + (%g)i\n", realPart, imagePart);
}
#endif
It successfully worked with stuff like that:
wComplex A(1, 2);
wComplex B(2, 4);
wComplex C(2, 1);
(A==C) is true.
There is another class - queue-like. But it should control the new pushed element for equality (in == meaning) of other elements.
#ifndef MYQueue_H
#define MYQueue_H
#include <stdio.h>
#include <queue>
template<typename T>
class myQueue : public std::queue<T>{
public:
myQueue(){
printf("new myQueue successfully created\n");
}
void push (const T& x){
myQueue* tmp = new myQueue;
myQueue* old = new myQueue;
old = this;
bool MATCH = false;
while(!old->empty()){
T el = old->front();
if(el == x){
MATCH = true;
tmp->push(x);
}
else
tmp->push(el);
old->pop();
}
if(!MATCH)
tmp->push(x);
this = *tmp;
delete tmp;
delete old;
}
};
#endif
So, now there is one problem
myqueue.h: In member function ‘void myQueue<T>::push(const T&) [with T = wComplex]’:
shit.cpp:23: instantiated from here
myqueue.h:26: error: no match for ‘operator==’ in ‘el == x’
wcomplex.h:36: note: candidates are: bool wComplex::operator==(wComplex&)
myqueue.h:36: error: lvalue required as left operand of assignment
make: *** [compile] Error 1
Actually, I can't understand why no match for ‘operator==’ in ‘el == x’
And what should I do? Any ideas
UPD: and how can I replace this element by tmp?
It's something wrong with this = *tmp;

You have a const reference to T in push() but your operator== only accepts non-const references.
bool wComplex::operator==(wComplex &El)
should be
bool wComplex::operator==(wComplex const &El) const
Or, optimally, your operator== should be a free function:
bool operator==(wComplex const & Left, wComplex const & Right) {
}
If you don't want outside access to the member variables of wComplex, you'll need to make the operator a friend function:
class wComplex {
...
friend bool operator==(wComplex const & Left, wComplex const & Right);
...
};
EDIT: On the updated question:
You cannot assign to this. this is of type T * const - since it wouldn't make sense to modify it. What you're trying to do is to change an external variable which points to the current class, you cannot do that from inside a class member function unless this external variable is passed in as an argument.
I think you need to make a "queue" class which manages "node" class instances - trying to combine a container and the contained elements isn't really a good idea
Also, inheriting standard library containers is rarely a good idea. If you want to use a std::queue then make a member variable.

Change:
bool wComplex::operator==(wComplex &El){
into:
bool wComplex::operator==(const wComplex &El) const {

One tips for the future:
The const keyword, either you put it nowhere, or everywhere you can.
Obviously, everywhere you can is better.

Related

segfault with self-declared hash function

ChunkCorner.h
#pragma once
#include <filesystem>
#include <iostream>
class ChunkCorner
{
public:
int x;
int y;
std::filesystem::path to_filename();
};
size_t hf(const ChunkCorner &chunk_corner);
bool eq(const ChunkCorner &c1, const ChunkCorner &c2);
ChunkCorner.cpp:
fwiw: The hf and eq function implementation is based on the C++ Book p. 917.
#include "ChunkCorner.h"
using namespace std;
size_t hf(const ChunkCorner &chunk_corner)
{
return hash<int>()(chunk_corner.x) ^ hash<int>()(chunk_corner.y);
}
bool eq(const ChunkCorner &c1, const ChunkCorner &c2)
{
return c1.x == c2.x && c1.y == c2.y;
}
[...]
In another bit of code I use the class as follows:
unordered_set<ChunkCorner, decltype(&hf), decltype(&eq)> chunks_to_load {};
ChunkCorner c {1,2};
chunks_to_load.insert(c);
On the insert call I get a segfault (determined using breakpoints).
I use VS Code and when I launch the program in debug mode, it jumps to the following bit on segfault in hashtable_policy.h:
__hash_code
_M_hash_code(const _Key& __k) const
{
static_assert(__is_invocable<const _H1&, const _Key&>{},
"hash function must be invocable with an argument of key type");
return _M_h1()(__k);
}
I am new to C++ and have trouble understanding what the issue is and I am not sure how to proceed debugging...
You need to pass the hash and equals functions to your constructor. You've declared their type in the type arguments, which is going to be a pointer to function, but you haven't passed them in. So they're likely being zero initalized, so nullptr. Using them correctly should be done like this:
unordered_set<ChunkCorner, decltype(&hf), decltype(&eq)> chunks_to_load {16, hf, eq};
However, what I recommend is rewrite your Hash/Equals functions into function objects. This way, the default operations will work properly.
struct MyHasher {
size_t operator()(const ChunkCorner &chunk_corner) const
{
return hash<int>()(chunk_corner.x) ^ hash<int>()(chunk_corner.y);
}
};
struct MyEq {
bool operator()(const ChunkCorner &c1, const ChunkCorner &c2) const
{
return c1.x == c2.x && c1.y == c2.y;
}
};

Class with an unordered set of itself

I simplified my question to this. Can I create a class that has an unordered set with template type itself? To be specific, for example a Square that has a pointer to an unordered set of neighbors. I got stuck trying to integrate a hash function with the class itself.
Here is my code:
#include <iostream>
#include <unordered_set>
#define SIZE 200
#define MASTER 0
class Square;
namespace std{
template<>
struct hash<Square> {
std::size_t operator () (Square const &v) const
{
return v.r;
}
};
}
class Square{
public:
int c1, c2;
int r;
std::unordered_set<Square> *neigh;
Square() {
neigh = new std::unordered_set<Square>();
}
~Square(){
delete neigh;
}
bool operator==(const Square& second) {
return this->r == second.r
&& this->c1 ==second.c1
&& this->c2 == second.c2;
}
};
int main(int argc, char *argv[]) {
Square sq;
Square tt;
sq.neigh->insert(tt);
}
I tried to compile using g++ and FLAGS = --std=c++17 -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -ggdb. The error received was gigantic, starting with:
test.cpp: In member function ‘std::size_t std::hash<Square>::operator()(const Square&) const’:
test.cpp:15:20: error: invalid use of incomplete type ‘const class Square’
15 | return v.x;
I don't know what is the correct approach to this situation. Please take into consideration this is my simplified code version of what I need, so I really need a neighbors field.
To solve the problem you're asking about, just declare std::hash<Square>::operator() before the Square definition, but don't implement it:
namespace std{
template<>
struct hash<Square> {
std::size_t operator() (Square const &) const;
};
}
Then after the Square definition, define the std::hash<Square>::operator():
namespace std {
std::size_t hash<Square>::operator() (Square const& v) const
{
// return calculation
}
}
You have a problem with the insert too. You copy an object with a pointer and then destroy the same pointer twice. To remedy that, use a std::unique_ptr<std::unordered_set<Square>> which helps since you'll get a compilation error if you try copying it.
class Square{
public:
std::unique_ptr<std::unordered_set<Square>> neigh;
Square() : neigh{std::make_unique<std::unordered_set<Square>>()} {}
// no destructor needed
bool operator==(const Square& second) const { // should be const
// ...
}
};
You then have to move objects into place:
sq.neigh->insert(std::move(tt));
or emplace them:
sq.neigh->emplace(...constructor arguments...);
Demo

C++ - Creating a Copy function without = assignment for a Dynamic String Array

Trying to write a copy function for a dynamically allocated array.
In my header file I have:
#include <memory>
#include <string>
using std::string;
using std::unique_ptr;
using std::make_unique;
class StringSet{
public:
//create an empty set
StringSet() = default;
StringSet(int capacity);
//copy a set
StringSet(const StringSet&);
StringSet& operator[](const int);
//Insert a string to the set
bool insert(string);
//Remove a string from the set
bool remove(string);
//Test whether a string is in the set
int find(string) const;
//Get the size of the set
int size() const;
//get string at position i
string get(int i) const;
//Return the set union of the set and another StringSet
StringSet setunion(const StringSet&) const;
//Return the intersection of the set and another StringSet
StringSet intersection(const StringSet&) const;
//Return the set diffference of the set and another StringSet
StringSet difference(const StringSet&) const;
//prevent default copy assignment
StringSet& operator=(const StringSet&) = delete;
int NOT_FOUND = -1;
static constexpr int def_capacity {4};
private:
int arrSize {def_capacity};
int currentSize {0};
unique_ptr<string[]> arr {make_unique<string[]>(def_capacity)};
};
In my implementation file I have:
#include "StringSet.h"
#include <iostream>
#include <utility>
StringSet::StringSet(int capacity)
: arrSize{capacity},
arr{make_unique<string[]>(capacity)}
{
}
StringSet::StringSet(const StringSet& a)
{
auto a2 = StringSet(currentSize);
for (auto i=0; i < currentSize ; i++ )
{
a2[i] = a[i];
}
}
Compiler error:
error: constructors may not be cv-qualified
error: no match for 'operator=' (operand types are 'StringSet' and 'std::string {aka std::basic_string<char>}')
error: passing 'const StringSet' as 'this' argument discards qualifiers [-fpermissive]
error: use of deleted function 'StringSet& StringSet::operator=(const StringSet&)'
My assignment has overloaded the assignment operator= and thus I'm not able to use that here. Is there another way of implementing a copy function without using the assignment operator - is there anything in std::string that allows us to copy contents easier in this manner?
If there's anything else I need to add here for details please let me know.
Thank you.
The problem with this code:
StringSet::StringSet(const StringSet& a)
{
auto a2 = StringSet(currentSize);
for (auto i=0; i < currentSize ; i++ )
{
a2[i] = a[i];
}
}
is that, even if it compiled, you're never actually initializing the members of this... you're initializing some temporary a2 that goes out of scope at the end of the constructor. You actually want:
StringSet::StringSet(const StringSet& a)
: StringSet(a.arrSize)
{
currentSize = a.currentSize;
for (auto i=0; i < currentSize; i++ )
{
arr[i] = a.arr[i];
}
}
Also, your operator[] returns a StringSet& where it should probably return a std::string&.
Also, you should avoid bringing names into the global namespace like you're doing. Keep it local. Writing std:: is not a burden.

Priority queue of struct's pointers

I know that there are similar threads but after spending an hour trying to force my program to work, I decided to ask for a help.
First of all. I've thought that I know c++ pretty well since I tried something which is very simple in PHP(programming language which I know best) but very complexed in c++ (at least very complexed for me). So I want to create priority_queue of struct's pointers. It's obvious that I need to create my own compare function. So I tried this code:
#include <iostream>
#include <list>
#include <queue>
using namespace std;
typedef struct MI
{
int nr;
int koszt;
bool operator<(const MI& a, const MI& b) {
return a.koszt > b.koszt;
}
} miasto, *miasto_wsk;
int main()
{
priority_queue<miasto_wsk> q;
miasto_wsk mi;
mi = new miasto;
mi->nr = 1;
mi->koszt = 2;
q.push(mi);
}
And when I tried to compile my program I ended up with compilation error:
test.cpp:11:44: error: ‘bool MI::operator<(const MI&, const MI&)’ must take exactly one argument
Can you explain me what I'm doing wrong and explain me how all this stuff with structs compare works(or give me a good tutorial/article which explains that from the beginning)
EDIT:
I changed my code to this:
#include <iostream>
#include <list>
#include <queue>
using namespace std;
typedef struct miasto
{
int nr;
int koszt;
} *miasto_wsk;
bool myComparator(miasto_wsk arg1, miasto_wsk arg2) {
return arg1->koszt < arg2->koszt; //calls your operator
}
int main()
{
priority_queue<miasto_wsk, vector<miasto_wsk>, myComparator> q;
miasto_wsk mi;
mi = new miasto;
mi->nr = 1;
mi->koszt = 2;
q.push(mi);
}
And now I getting this error msg:
test.cpp: In function ‘int main()’:
test.cpp:19:64: error: type/value mismatch at argument 3 in template parameter list for ‘template<class _Tp, class _Sequence, class _Compare> class std::priority_queue’
test.cpp:19:64: error: expected a type, got ‘myComparator’
test.cpp:19:67: error: invalid type in declaration before ‘;’ token
test.cpp:24:7: error: request for member ‘push’ in ‘q’, which is of non-class type ‘int’
What is the problem? Maybe I should use copies of structs instead pointers to structs?
EDIT2
This code doesn't produce any compilation errors:
#include <iostream>
#include <list>
#include <queue>
using namespace std;
typedef struct miasto
{
int nr;
int koszt;
bool operator< (const miasto& rhs)
{
koszt > rhs.koszt;
}
} *miasto_wsk;
int main()
{
priority_queue<miasto_wsk> q;
miasto_wsk mi;
mi = new miasto;
mi->nr = 1;
mi->koszt = 22;
q.push(mi);
}
So #Angew idea seems to be wrong.
EDIT3:
This is my final code. It not only compile without errors but also doing exactly what I want. Thank you so much #Angew
#include <iostream>
#include <list>
#include <queue>
using namespace std;
typedef struct miasto
{
int nr;
int koszt;
} *miasto_wsk;
struct MyComparator {
bool operator() (miasto_wsk arg1, miasto_wsk arg2) {
return arg1->koszt > arg2->koszt; //calls your operator
}
};
int main()
{
//priority_queue<miasto_wsk, vector<miasto_wsk>, myComparator> q;
priority_queue<miasto_wsk, vector<miasto_wsk>, MyComparator> q;
miasto_wsk mi;
mi = new miasto;
mi->nr = 1;
mi->koszt = 22;
q.push(mi);
miasto_wsk mi1;
mi1 = new miasto;
mi1->nr = 2;
mi1->koszt = 50;
q.push(mi1);
miasto_wsk mi2;
mi2 = new miasto;
mi2->nr = 3;
mi2->koszt = 1;
q.push(mi2);
cout << q.top()->koszt << endl;
q.pop();
cout << q.top()->koszt << endl;
q.pop();
cout << q.top()->koszt << endl;
q.pop();
}
There are multiple issues here.
When you define an operator inside a class, it automatically takes a parameter of the class type as its first argument, and you must not create a parameter for it. So you either keep the operator in the class, like so:
struct MI {
bool operator< (const MI&);
};
or declare the operator as free-standing:
struct MI {
//...
};
bool operator< (const MI&, const MI&);
Second, your priority_queue stores pointers to MI, not instances of MI, so the operator will not be called anyway. You must provide a comparator when defining the priority queue, like this (EDITED):
struct MyComparator {
bool operator() (miasto_wsk arg1, miasto_wsk arg2) {
return *arg1 < *arg2; //calls your operator
}
};
int main() {
priority_queue<miasto_wsk, vector<miasto_wsk>, MyComparator> q;
//...
}
Third is just a style thing: I'd suggest you name the class directly miasto rather than making it just a typedef. It's more natural in C++.
The error, if you read it again, tells you exactly what's wrong: That the MI::operator< function should take only one argument instead of two.
If you have operator< in the class (like you do) then the function takes only one argument and that is the other object to compare this with. If you create operator< as a free standing function (i.e. not part of the class) then it has to take two arguments.
Your comparison operator is a member function, so it should only take one parameter, for theRHS:
bool operator<(const MI& rhs) {
koszt > rhs.koszt;
}
Another option is to declare it as a non-member function:
struct MI {};
bool operator<(const MI& a, const MI& b) {
return a.koszt > b.koszt;
}
Use friend keyword to put the operator < in the global scope
typedef struct MI
{
int nr;
int koszt;
friend bool operator<(const MI& a, const MI& b)
{
return a.koszt > b.koszt;
}
} miasto, *miasto_wsk;

maintaining pair of elemts using own class template

I made my own class template to maintain pair of elements of any type of objects. Now I am going to use this template for another own class MyPoint. this contain 3D cordinates of a point. I think I need to modify this further as my final objective is to use this PairInfor<MyPoint> as a vector<PairInfor<MyPoint> > and again vector<vector<PairInfor<MyPoint> > >. SO, I need your support to modify this as I do not have very knowledge to prepare this types of templates.
I got assistant from some other classes and books, but i need to include most common functions to this. Can anyone help please?
Here is my template class;
// class to accomadate two values
//-------------------------------
#include <stdlib.h>
#include <iostream>
template <class Type>
class PairInfor {
private:
/// two elements of the pair
Type x[2];
public:
// Default constructor.
PairInfor() { x[0] = x[1] = -1; }
// other Constructors.
PairInfor(Type xv, Type yv) {
x[0] = xv; x[1] = yv;
}
PairInfor(const Type *v) { x[0] = v[0]; x[1] = v[1]; }
//constructor for Coping
PairInfor(const PairInfor &v) { x[0] = v.x[0]; x[1] = v.x[1]; }
// Destructor.
~PairInfor() {}
// assignament
PairInfor& operator=(const PairInfor &v)
{ x[0] = v.x[0]; x[1] = v.x[1];
return *this;
}
// Element access, for getting.
Type V1() const { return x[0]; }
// Element access, for getting.
Type V2() const { return x[1]; }
// Element access, for getting.
Type operator[] (int i) const { return x[i]; }
// Element access, for writing.
Type &V1() { return x[0]; }
// Element access, for writing.
Type &V2() { return x[1]; }
// Element access, for writing.
Type &operator[] (int i) { return x[i]; }
// Return a constant reference to the pair
const class PairInfor &infor() const { return *this; }
// Return a reference to the pair
PairInfor &infor() { return *this; }
// comparing two pair packets
friend bool operator == (const PairInfor &v1, const PairInfor &v2)
{
return v1.x[0] == v2.x[0] && v1.x[1] == v2.x[1];
}
};
When I use this template class, I get the following error too.
\include\PairInfor.hpp In constructor `PairInfor<Type>::PairInfor() [with Type = MyPoint]':
\myprogf.cpp instantiated from here
\include\PairInfor.hpp invalid conversion from `int' to `char*'
\include\PairInfor.hpp initializing argument 1 of `MyPoint::MyPoint(char*)'
\Makefile.win [Build Error] [myprogf.o] Error 1
How do I solve this error. Is the error with my default constructor in PairInfor. How do I solve this please?
Thanks in advance.
The following line doesn't work for any type:
PairInfor() { x[0] = x[1] = -1; }
You are trying to assign an integer, but Type may not support that. MyPoint doesn't, hence the error.
You should default-initialize your members:
PairInfor() : x() {}
Note that std::pair might cover your needs already.