Why is this assert failing? - c++

The assert in main.cpp is failing, and I don't understand why.
Here is string.hpp
class String
{
private:
int len;
char* str;
public:
String(char const* s); // C-string constructor
~String() {delete str;}; // destructor
char* const getString(); //get string for printing
};
inline bool operator==(String lhs, String rhs)
{
return std::strcmp(lhs.getString(),rhs.getString());
}
// Define operator!= in terms of ==
inline bool operator!=(String const& lhs, String const& rhs)
{
return !(lhs == rhs);
}
and here is string.cpp
String::String(char const* s) // C-string constructor
{
len = std::strlen(s);
str = new char[len+1];
std::strcpy(str,s);
}
char* const String::getString()
{
return str;
}
and here is main.cpp
#include <cassert>
int main()
{
String c = "c";
String d = "d";
assert(c == c);
assert(c != d);
}
I tried to include only the essential code. I left out a lot of the obvious includes. The assert(c == d) is failing and I don't understand why. The operator overload of == should have returned a true result.

std::strcmp returns 0 if the strings are equal. So your operator== will return false for equal strings and true else.
You could, for instance, switch the implementations of == and != around,

strcmp returns 0 when its arguments have equal contents.
So add a comparison with 0 to your operator==:
inline bool operator==(String const& lhs, String const& rhs)
{
return std::strcmp(lhs.getString(), rhs.getString()) == 0;
}
Also, since you probably don't want to copy the arguments each time you call operator==, I'd recommend passing them by reference.

Related

c++ operator overload with string comparing

hello i have problem in my school c++ lab, my bool operator > should be return true if lhs is greater than rhs, however it always return false. i try print out lhs.tostring(), it show the number correctly.
my lhs and rhs is a string value.
due to some confidence restrict from my school work, i am not allow to post all the function of my work.
Updated information: ithis lab only can use c++14 and can't include any additional lib. The int value is written in string, and need to compare which is bigger. Assuming there is no negative and any letter other than number
some part of my header file
#include <cstring>
#include <iostream>
namespace CS170
{
class BigNum
{
public:
/* Constructor of BigNum object.
Takes in a character string and
constructs a BigNum */
BigNum(const char * rhs = "0");
/* one of rule of 3 need destructor */
~BigNum();
/* Return a character pointer pointing
to the start of the array representing the big num */
const char * toString() const;
/* Return how many digits the number has */
size_t getNumDigits() const;
BigNum & operator =(const BigNum & rhs);
private:
size_t len;
char* num;
};
}
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs);
cpp
namespace CS170
{
BigNum::BigNum(const char * rhs )
:len{strlen(rhs)}, num{new char[len+1]}
{
strcpy(num,rhs);
}
BigNum::~BigNum()
{
}
const char * BigNum::toString() const
{
return num;
}
size_t BigNum::getNumDigits() const
{
return len;
}
}
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs)
{
CS170::BigNum left_value{lhs};
CS170::BigNum right_value{rhs};
std::cout << std::endl;
std::cout << left_value.toString() << " " << right_value.toString() <<
std::endl;
/*this don't work for comparing**/
if(left_value.toString() > right_value.toString())
return true;
else
return false;
}
left_value.toString() > right_value.toString()
This does not do what you think it does. toString() returns a const char*, a pointer to some data. Formally the behaviour of > in your case is undefined since the pointers are not part of the same array, and even if they were, the result would not depend on the string contents.
To check the lexicogrammatical order of strings, you should use the right tool for it, for instance std::string::operator>:
std::string lhs_string{left_value.toString()};
std::string rhs_string{rght_value.toString()};
if (lhs_string > rhs_string)
// ...
// note: here you could simply do return lhs_string > rhs_string;
If you're using a recent compiler and C++17 is an option, you could also use those tools without copying data around:
#include <string_view>
const char* lhs = "programming";
const char* rhs = "language";
std::string_view lhs_string{lhs};
std::string_view rhs_string{rhs};
lhs_string>rhs_string // lexicogrammatical order
live demo
const char* cannot be compared in the way you are trying to. You have to use strcmp. Example usage would look like:
if (strcmp(left_value.toString(), right_value.toString()) > 0)
{
return true;
}
The last part of the function could even be simplified to:
return strcmp(left_value.toString(), right_value.toString()) > 0;
is nearly there but i don't work if compare 11 > 2, as is still read only the first string.
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs)
{
CS170::BigNum left_data{lhs};
CS170::BigNum right_data{rhs};
int result = strncmp(left_data.toString(), right_data.toString(),20);
return result > 0;
}

Class conversion not working as expected

I defined simple conversion method
operator string() { return /*...*/; }
When I call it directly
obj.operator string()
It works fine, but when I call it this way ...
(string)obj
Result is empty string.
What's going on? (I'm using gcc c++14) (Can post code If needed)
Class
class String : public std::string {
std::string str_;
public:
String() {};
String(const String & s) {
str_ = std::string(s.str_);
};
String(String && s) {
str_ = std::string(s.str_);
};
String(const string & s) {
str_ = std::string(s);
};
String(const char * s) {
str_ = std::string(s);
};
char & operator[](size_t i) {
return str_[i];
};
String & operator=(const String & str) {
if (this != &str) {
str_ = str.str_;
}
return *this;
};
String & operator=(String && str) {
if (this != &str) {
str_ = str.str_;
}
return *this;
};
bool operator==(const String & str) {
return str_ == str.str_;
};
bool operator!=(const String & str) {
return str_ != str.str_;
};
operator string() {
return str_;
};
};
The problem is that your class is deriving from std::string.
Remove the : public std::string part and the conversion operator will be used.
You class is already declaring an std::string member (so it uses the "has-a" approach) and doesn't need the "is-a" approach.
By the way deriving from standard library classes is almost always a bad idea (they were not designed for that).

std::map key not found even though the entries are identical

I'm learning C++ and I've been writing a wrapper for std::map and std::string, and I've stumbled upon a problem. Whenever I add something to the map using a string as key, once I try to access that item using the exact same key it says the key is out of bounds of the map. Here's my code (irrelevant parts left out):
ADictionary.h
#ifndef ADICTIONARY_H
#define ADICTIONARY_H
#include <map>
...
template<typename KEY, typename VALUE>
class ADictionary {
public:
...
VALUE operator [](KEY key) const {
return value.at(key);
}
void add(KEY key, VALUE value) {
this->value.insert(std::make_pair(key, value));
}
...
private:
std::map<KEY, VALUE> value;
};
#endif
AString.cpp
#include "AString.h"
AString::AString() {
value = "";
}
AString::AString(const char character) {
value = character;
}
AString::AString(const char * characters) {
value = characters;
}
AString::AString(std::string text) {
value = text;
}
...
AString::operator const char *() const {
return value.c_str();
}
AString::operator const std::string() const {
return value;
}
...
ABoolean AString::operator<(AString & text) const {
return getLength() < text.getLength();
}
ABoolean AString::operator>(AString & text) const {
return text < *this;
}
ABoolean AString::operator==(AString & text) const {
return value == text.value;
}
ABoolean AString::operator!=(AString & text) const {
return !(text == *this);
}
AString & AString::operator=(AString & text) {
value = text.value;
return *this;
}
...
The code which uses the above
ADictionary<AString, AString> test;
AString a = "a";
AString b = "b";
test.add(a, b);
std::cout << test[a]; // Error occurs here, according to the program "a" is not a key in the map
I hope someone can explain to me what's going wrong. I've tried creating a dictionary with the default std::string as types and it worked correctly:
ADictionary<std::string, std::string> test;
std::string a = "a";
std::string b = "b";
test.add(a, b);
std::cout << test[a]; // No error this time
As I've said, I'm pretty new to C++ so there may be other errors. If so, feel free to point them out.
Thanks!
EDIT:
AString.h
#ifndef ASTRING_H
#define ASTRING_H
#include <string>
#include "ABoolean.h"
#include "AInteger.h"
#include "AList.h"
class ABoolean;
class AInteger;
template<typename VALUE>
class AList;
class AString {
public:
AString();
AString(const char);
AString(const char *);
AString(std::string);
~AString();
operator const char *() const;
operator const std::string() const;
operator const AInteger() const;
ABoolean operator<(AString &) const;
ABoolean operator>(AString &) const;
ABoolean operator==(AString &) const;
ABoolean operator!=(AString &) const;
AString & operator=(AString &);
AString & operator+(AString &);
AString & operator+=(AString &);
void clear();
ABoolean contains(AString) const;
AInteger getIndex(AString) const;
AInteger getLength() const;
AList<AString> getSplit(AString) const;
AString getSubstring(AInteger, AInteger) const;
void removeRange(AInteger, AInteger);
void removeSubstring(AString);
void toLowercase();
void toUppercase();
private:
std::string value;
};
AString & operator+(const char, AString &);
AString & operator+(const char *, AString &);
#endif
Your string operators appear to be incorrect.
std::map uses the less than operator by default. While you provide one for AString, the only thing it does is check the length of the string. What if the two strings are of equal length?
The correct thing to do is to lexicographically compare the characters in the string. While there is a standard library function to do this, you can use operator < of the std::string values in your class:
friend bool operator<(AString const& a, AString const& b)
{
return a.value < b.value;
}
EDIT: You may also wish to remove your conversion operators, or at least make them explicit, which prevents surprising and unwanted implicit conversions. Constructors taking one parameter (other than copy or move constructors) should also be declared explicit.

C++ - no operator found

I have a vector filled with values of a custom type and the find() algorithm is complaining that it cannot find a suitable == operator for the value comparison. I've implemented it like this:
bool Ship::operator==(const Ship& source) {
return (_type == source._type &&
_damagedSquares == source._damagedSquares &&
_orientation == source._orientation && _state == source._state);
}
I've also tried the "friend" method approach but that doesn't work either.
The class itself is structured like this:
class Ship {
private:
ShipType _type;
int _damagedSquares;
ShipOrientation _orientation;
ShipState _state;
public:
Ship();
Ship(ShipType type);
~Ship();
bool operator==(const Ship& source);
};
What am I doing wrong here?
Additional info:
std::vector<Ship> remainingShips;
MultiArray& squares = opponentGridCopy.GetSquares();
for (RowIterator rowIterator = squares.begin(); rowIterator != squares.end();
++rowIterator) {
for (ColumnIterator columnIterator = rowIterator->begin();
columnIterator != rowIterator->end(); ++columnIterator) {
Square* current = &(*columnIterator);
SquareState currentState = current->GetState();
if (currentState != SquareState::Hit)
current->SetState(SquareState::Vacant);
Ship* potentialShip = current->GetOwner();
if (potentialShip != nullptr) {
int damagedSquares = potentialShip->GetDamagedSquares();
if (!damagedSquares) {
current->SetState(SquareState::Populated);
break;
}
if (remainingShips.empty() ||
std::find(remainingShips.begin(), remainingShips.end(),
potentialShip) ==
remainingShips.end()) // should be *potentialShip
remainingShips.push_back(*potentialShip);
}
}
}
return remainingShips;
I was passing a pointer as a compare value...
Simply dereferenced it and find() works now.
Declare your comparison operator like so:
bool Ship::operator==( const Ship &source ) const
Note the trailing const.
Ship* potentialShip = ...
std::find(remainingShips.begin(), remainingShips.end(), potentialShip)
you're trying to find a pointer while the vector where the search is performed is defined as
std::vector<Ship> remainingShips;
you're comparing a pointer with a Ship object and thus your comparison is wrong
bool Ship::operator==(const Ship& source) // Accepts a Ship reference, not a pointer
To fix it either dereference the pointer or change your comparison function.
Your
bool operator==(const Ship& source);
Should be const as well, namely
bool operator==(const Ship& source) const;
But actually, I prefer to have symmetric operators, not as member methods.
Consider:
Class Ship
{
private:
ShipType _type;
int _damagedSquares;
ShipOrientation _orientation;
ShipState _state;
public:
Ship();
Ship(ShipType type);
~Ship();
static bool eq(const Ship& s0, const Ship& s1)
{
return (s0._type == s1._type &&
s0.damagedSquares == s1._damagedSquares &&
s0._orientation == s1._orientation &&
s0._state == s1._state);
}
};
inline bool operator==(const Ship& s0, const Ship& s1)
{
return Ship::eq(s0, s1);
}

Problem with operator ==

I am facing some problem with use of operator == in the following c++ program.
#include < iostream>
using namespace std;
class A
{
public:
A(char *b)
{
a = b;
}
A(A &c)
{
a = c.a;
}
bool operator ==(A &other)
{
return strcmp(a, other.a);
}
private:
char *a;
};
int main()
{
A obj("test");
A obj1("test1");
if(obj1 == A("test1"))
{
cout<<"This is true"<<endl;
}
}
What's wrong with if(obj1 == A("test1")) line ?? Any help is appreciated.
strcmp returns 0 when the strings are equal, so you want:
return strcmp(a, other.a) == 0;
You should also use a const reference like Cătălin Pitiș says in his answer, because then you can use temporary objects with the operator, and you should also make the method itself const (since it doesn't modify the object) as Andreas Brinck says in the comments below. So your method should be:
bool operator ==(const A &other) const
{
return strcmp(a, other.a) == 0;
}
bool operator ==( const A &other)
Use const reference, so a temporary object that is constructed in if statement can be used as parameter for operator==.
It looks to me like you want this in your operator:
strcmp(a, other.a) == 0
strcmp returns 0 when strings match, and a number indicating whether the comparison is greater or less than otherwise.
Your error is that you create an instant value and pass it as reference to the operator== method. But your error is in your operator definition that should be:
bool operator==(const A& other) const
the body being the same.