C++ plus operator not working with const char and others - c++

Hello i made a variable storage like string and this is the source
class str
{
private:
const char * _mystring;
public:
// Using this function to made new str
str(const char * _str) { _mystring = _str; }
// Get the content of this str
const char * read() { return _mystring; }
// Get the content in char *
char * read_c() { return strdup(_mystring); }
// Operator for equal action with extern const char
str & operator = (const char * _str) { _mystring = _str; return *this; }
// Operator for equal action with extern str storage
str & operator = (str _str) { _mystring = _str.read(); return *this; }
// Operator for add action
str operator + (const char * _str) {
return str(strcat(read_c(), _str));
}
// Operator for add action with new str
str operator + (str & _str) {
return str(strcat(read_c(), _str.read()));
}
};
and this is my test program
int main() {
str var1("Var1"); // No problem
str var2("Var2"); // No problem
str var3 = var1 + var2; // No problem
str var4 = var1 + "tempStr"; // I got runtime error !
str var5 = "tempStr" + var2; // I got error before compile
cout << var1.read() << endl;
cout << var2.read() << endl;
cout << var3.read() << endl;
cout << var4.read() << endl;
return 0;
}
what is the problem that i can't create something like var3 and var4 and i got error (i get error while i want to merge const char with my str ... i set + operator but there is problem for when i want to merge const char with my str (not my str with const char... on this action, there is no problem)
but wait i got error (debug (close program)) after compile and print var7 too !

For str var3 = "tempTxt0" + "tempTxt1" + "tempTxt2"; // Error:
This does not work because the compiler sees these types (omitting variable names): str = const char* + const char* + const char *. Adding char pointers together is not what you want. However, if you only had one of them to be type of class str, it would work. E.g. str = str(const char*) + const char* + const char * would call the str::operator+, which returns a new object of type str and the rest will follow the same way.
For str var4 = "tempTxt3" + var1; // Error:
This does not work because you declare operator+ as a member function. Again compiler sees these types (omitting variable names): str = const char* + str. There is no operator+ declared for const char* as the first operand and str as the second operand. You have a member operator+ but that operator works on a class str so you would need a class str on the left hand side; as in str + const char*. Think of it like a function call because it is exactly a member function call. It is the same as typing str = str.operator+("text"). Now you see, str = "text".operator+(str) does not work because it does not exist.
If you declared a non-member function str operator+(const char* first, const str& second);, it would work. The compiler will look for operators that matches what you want in outer namespace scopes of the parameters up to the global scope (this is called ADL). But there is a better way:
Declare str operator+(const str& lhs, const str& rhs);. If you declare your operators this way in the namespace scope of the class str, then compiler will use ADL (on Wikipedia) using the second argument's type (which is class str) and find this operator. Then, the compiler can see that class str has a non-explicit constructor which can take const char*: str(const char * str). It can then create a temporary object of class str and use the operator+ you defined.
So for your example, as you do not have any namespaces, you would need this at its simplest (notice I have added a few const keywords):
class str
{
private:
const char * _mystring;
public:
// Using this function to made new str
str(const char * _str) { _mystring = _str; }
// Get the content of this str
const char * read() const { return _mystring; }
// Get the content in char *
char * read_c() const { return strdup(_mystring); }
// Operator for equal action with extern const char
str & operator = (const char * _str) { _mystring = _str; return *this; }
// Operator for equal action with extern str storage
str & operator = (str _str) { _mystring = _str.read(); return *this; }
};
// Operator for add action with new str
str operator+ (const str& lhs, const str& rhs) {
return str(strcat(lhs.read_c(), rhs.read()));
}
P.S.
Your example has more problems. read_c duplicates the string (let say) of 10 bytes and you concatenate more bytes at the end of it. That is an overflow because your duplicated buffer is 10 bytes. You have to allocate and free the memory properly but that is for another question I guess. E.g.
str operator+(const str& lhs, const str& rhs) {
const std::size_t ls = lhs.size();
const std::size_t rs = rhs.size();
char* n = new char[ls + rs + 1];
std::memcpy(n, lhs.read(), ls);
std::memcpy(n + ls, rhs.read(), rs);
n[ls + rs] = '\0';
return str(n);
}
Then you still have the problem of when to delete.

str var3 = "tempTxt0" + "tempTxt1" + "tempTxt2"; // Error
str var4 = "tempTxt3" + var1; // Error
In these lines you're trying to add 2 pointers to some static memory (in other words your operator isn't called)
On the left side of the operator plus needs to be your class
Having an empty (only with \0) instance of your class will fix your error (as you might have already noted):
str var4 = str("") + "tempTxt3" + var1; //now it is okay
Also, note that strcat doesn't allocate memory for concatening, you have to do it with realloc yourself

When you override a binary operator such as +, the left operand has to be the object in question. The reason you get errors is because the left operand is a string constant and this the default + is used.
You need to create friend functions for these operators that accept a const char * for the first parameter and either str or a const char * for the second parameter.

str var4 = var1 + "tempStr"; // I got runtime error !
in this case following operator+ overload is called:
str operator + (const char * _str) {
return str(strcat(read_c(), _str));
}
you call strcat on a pointer which points to a buffer not large enough to contain both current string and _str. The fastest solution is to use std::string, otherwise you need to allocate large enough buffer and also remember to keep care of its lifetime (adhere to rule of three etc.)
str var5 = "tempStr" + var2; // I got error before compile
You need a global operator overload of following signature:
str operator + (const char * _str, const str& s);

Related

Error when converting to char * to my custom class(MyString) object

I am trying to write my own string class using the library for preparing my exam .But I had this error saying that
main.cpp:9:22: error: no match for ‘operator+’ (operand types are ‘const
char [5]’ and ‘MyString’)
MyString c = "Hola" + b;
My main is like this. It works file then "Hola" and b change place.
MyString b("Mundo\n");
MyString c = "Hola" + b;
I think it doesn't call the constructor there .
My class has these in private.
char * _str
int _length
My constructor.
MyString::MyString(const char * str){
int length = 0;
for(char c = str[0]; c != '\0' ; c++)
++length;
_length = length;
_str = new char[length+1];
strcpy(_str,str);
}
And my + overload
const MyString MyString::operator+(const MyString& mS) const{
char * tempChar = new char[_length + mS._length];
MyString tempStr(tempChar);
delete[] tempChar;
strcpy(tempStr._str,_str);
strcat(tempStr._str,mS._str);
return tempStr;
}
Edit : I solved it by making operator+ a friend function but I want to know why
when you write
MyString b{"Mundo\n"};
MyString c = b + "Hola";
string literal will be sent your operator+ function paremeter, and MyString object created with "Holla"(You can test it with write a text in your constructor).
Besides, when you didn't write your friend function and write
MyString b{"Mundo\n"};
MyString c = "Holla" + b;
compiler will search function which has first parameter is const char * and can't find.(and no match error show this). this is the reason for writing friend function.
I hope you can understand reason

setting an std::string data member from a derived class constructor

I have a derived class called Mystring that is derived from std::string, and I would like to set the value of the string that I am working with.
From my understanding to access the string object from std::string I would use *this to get the string that I am currently working with.
I would like to set *this to a string of my choosing, I did this my setting *this = n; but it crashes my code and returns a "Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffeef3ffff8)" my code is below:
So my question is, how can I set the value of std::string to something through my derived class. Much thanks!
class Mystring : public std::string
{
public:
Mystring(std::string n);
std::string removePunctuation();
std::string toLower();
};
Mystring::Mystring(std::string n)
{
*this = n;
}
std::string Mystring::removePunctuation()
{
long int L = length();
char *cstr = new char[L + 1];
strcpy(cstr, c_str());
//cout << cstr[L-1] << endl; // last character of c string
if(!isalpha(cstr[L-1]))
{
pop_back() ;
}
return *this;
}
std::string Mystring::toLower()
{
long int L = length();
char *cstr = new char[L + 1];
strcpy(cstr, c_str());
for(int i = 0; i < L;i++)
{
int buffer = cstr[i];
cstr[i] = tolower(buffer);
std::cout << cstr[i];
}
std::string returnstring(cstr);
delete [] cstr;
return returnstring;
}
int main() {
Mystring temp("dog");
std::cout << "Hello World";
return 0;
}
Style aside, the fundamental idea of using an assignment operator to "reset" an inherited subobject is not necessarily incorrect.
However, a conversion is required to get from std::string (the type of the RHS) to Mystring (the type of the LHS, i.e. *this). The only way to perform that conversion is to use the constructor Mystring(std::string). Except… you're already in it. Hence that function is effectively recursive and will repeat forever until you exhaust your stack.
You need to upcast *this to a std::string in order to make this work:
static_cast<std::string&>(*this) = n;
I do agree with the other people here that you shouldn't be deriving from std::string, and certainly not just to add a couple of utility functions that ought to be free functions taking std::string (perhaps in a nice namespace, though?).
Don't do it. Derivation provides no benefit in this situation.
Create your added functions as free functions that operate on a string. For example:
void remove_punctuation(std::string &s) {
if (!std::isalpha(s.back()))
s.pop_back();
}
void tolower(std::string &s) {
for (auto &c : s)
c = std::tolower(c);
}
Making either/both of these a member function serves no purpose and provides no benefit.
References
GOTW #84: Monoliths Unstrung
How Non-Member Functions Improve Encapsulation

SIMPLE string implementation in c++

I started writing a very simple implementation of a string class in c++, here is the code:
class String
{
public:
String()
{
this->_length = 0;
this->_size = 0;
this->_string = NULL;
}
String(const char* str)
{
this->_length = strlen(str);
this->_size = this->_length + 1;
this->_string = new char[this->_size];
strcpy_s(this->_string, this->_size, str);
}
~String()
{
if (this->_string != NULL)
{
delete[] this->_string;
this->_string = NULL;
}
}
String& operator+(const char* str)
{
String* temp = new String();
temp->_length = strlen(str) + strlen(this->_string);
temp->_size = temp->_length + 1;
temp->_string = new char[temp->_size];
strcpy_s(temp->_string, temp->_size, this->_string);
strcat_s(temp->_string, temp->_size, str);
return (String&)*temp;
}
int Length()
{
return this->_length;
}
private:
int _size;
int _length;
char* _string;
};
You can see that my implementation of operator+ is absolutely wrong, in fact there is a memory leak.
Writing the operator+= is way simpler because I can simply concatenate the char* with this->_string and return *this.
I need help with the operator+ implementation.
Note: This is homework so I don't want the solution the copy-paste but it would be awesome if someone could point me in the right direction...
Thanks
Edit:
I added the copy constructor:
String(const String& str)
{
this->_length = str._length;
this->_size = str._size;
this->_string = new char[this->_size];
strcpy_s(this->_string, this->_size, str._string);
}
the operator= and the operator+=:
String& operator=(const String& str)
{
if (this != &str)
{
this->_length = str._length;
this->_size = str._size;
this->_string = new char[this->_size];
strcpy_s(this->_string, this->_size, str._string);
}
return *this;
}
String& operator+=(const String& str)
{
this->_length = this->_length + str._length;
this->_size = this->_length + 1;
char* buffer = new char[this->_size];
strcpy_s(buffer, this->_size, this->_string);
strcat_s(buffer, this->_size, str._string);
delete[] this->_string;
this->_string = buffer;
return *this;
}
but there is still something wrong because if I run a while(true) loop like this:
while (true)
{
String a = String("string a");
String b = a;
b = "string b";
b += " string c";
}
the memory used by the process will increase continuously
You could reuse the operator+= in the operator+:
(The code below assumes that you have an operator+=, a copy constructor and an assignment operator which is NOT the case in the code you pasted).
EDIT: As suggested by Jerry Coffin the following operator should NOT be a class member but a free operator:
EDIT2: And to allow the compiler a bit more optimizations the first argument is not a const-reference anymore:
String operator+(String a, String const &b) {
a += b;
return a;
}
By this you can have a more simple operator+= and simply copy constructor and build the complex thing on the simple ones.
And do not forget:
You MUST implement a copy constructor and assignment operator. Otherwise the compiler generates it for you in a wrong way: The compiler generates code that simply copies the content. So it also copies the pointer but does not allocate new memory for the copy. Then you have two instances referencing the same memory and both try to deallocate it in the destructor which is undefined behavior.
One easy way to implement your operator+ is in terms of +=. Create a copy of the left operand, then use += to add the right operand to it, and finally return the result.
Also note that operator+ shouldn't usually be a member function -- it should normally be a free function. The basic difference is that as a member function, the left operand must already be a string for it to work. As a free function, your string constructor can be used to convert (for example) a string literal. For example, string+"something"; will work with a member function, but "something" + string; won't. With + overloaded as a free function, both of them will work.

concatenate const char * strings

I'm confused about char * and const char *. In my example I'm not sure how to put them together. I have several const char * strings I would like to concatenate to a final const char * string.
struct MyException : public std::exception
{
const char *source;
int number;
const char *cause;
MyException(const char *s, int n)
: source(s), number(n) {}
MyException(const char *s, const char *c)
: source(s), number(0), cause(c) {}
const char *what() const throw()
{
if (number != 0) {
char buffer[1024];
// why does this not work?
cause = strerror_r(number, buffer, 1024);
}
// how to concatenate the strings?
return source + ": " + cause;
}
};
You can store a std::string and still return a const char * from your what function.
struct MyException : public std::exception
{
private:
std::string message;
public:
MyException(const char *s, int n) {
char buffer[1024];
strerror_r(n, buffer, 1024);
message.reserve(strlen(s) + 2 + strlen(buffer));
message = s;
message += ": ";
message += buffer;
}
MyException(const char *s, const char *c) {
message.reserve(strlen(s) + 2 + strlen(c));
message = s;
message += ": ";
message += c;
}
const char *what() const throw()
{
return message.c_str();
}
};
Just use strcat() and strcpy() function from string.h.
http://www.cplusplus.com/reference/clibrary/cstring/strcat/
http://www.cplusplus.com/reference/clibrary/cstring/strcpy/
Also, since you don't have to modify original strings, the difference between const char* and char* doesn't matter.
Also don't forget to malloc() (reserve the space for) the required size of destination string.
This is how I'd implement this:
struct MyException : public std::exception
{
public:
const char *source;
int number;
const char *cause;
private:
char buffer[1024]; // #1
std::string message; // #2
std::string build_message() {
if (number != 0) {
cause = strerror_r(number, buffer, 1024); // use the member buffer
}
std::string s; // #3
s.reserve(strlen(source) + 2 + strlen(cause));
return s + source + ": " + cause;
}
public:
MyException(const char *s, int n)
: source(s), number(n), cause(), message(build_message()) {}
MyException(const char *s, const char *c)
: source(s), number(0), cause(c), message(build_message()) {}
const char *what() const throw()
{
return message.c_str(); // #4
}
};
Things to note:
The original code was using a local variable for a buffer. That is a bad idea, as the pointer stored in cause would be invalid the moment the scope ends.
For the concatenated message, dynamic allocation would be required. And that also means that cleanup of that storage would be required. I grabbed an existing tool that does that and provides string-like operations: std::string.
With std::string concatenation can be done with the + operator. Note how I asked it to reserve memory for the expected size. This is memory an optimization, and is not required: the string would allocate enough memory either way.
what cannot throw an exception, otherwise a call std::unexpected would arise. So the string cannot be allocated here.
If you must work with char* pointers, you will want to use strcat. strcat takes two arguments a char* and a const char* and appends the string pointed to by the const char* onto the char*. This means you first need to copy your first string over.
You'll want to do something like this:
char* Concatenate(const char* first, const char* second)
{
char* mixed = new char[strlen(first) + strlen(second) + 2 /* for the ': ' */ + 1 /* for the NULL */];
strcpy(mixed, first);
strcat(mixed, ": ");
strcat(mixed, second);
return mixed;
}
Isn't that just ugly? And, remember, because you've dynamically allocated the char* returned by that function the caller must remember to delete[] it. This ugliness and the need to ensure the caller cleans up in the right way is why you're better off using a string implementation such as std::string.
Allocate a buffer of size strlen(source) + strlen(cause) + 3 and use sprintf to create your message. Actually you can move this code to constructor so that what becomes simple getter.
If you really must use c-strings, you should look at strcat() to concatenate them together. However, since you are creating a custom exception, it would be reasonable to consider using std::string instead because it is more friendly to use in C++.

Overloading operator in C++ and dereference

I am practicing overloading operators in C++ right now and I have a problem.
I created String class, it has just to fields one is char array other is length.
I have a String "Alice has a cat" and when I call
cout<<moj[2];
I would like to get 'i', but now I am getting moj + 16u adress of moj + 2 sizeof(String)
When I call
cout<<(*moj)[2];
it works as it shoud but I would like to dereference it in overloaded operator definition. I tried many things but I can't find solution. Please correct me.
char & operator[](int el) {return napis[el];}
const char & operator[](int el) const {return napis[el];}
AND the whole code, the important things are down the page. It's compiling and working.
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstring>
using namespace std;
class String{
public:
//THIS IS UNIMPORTANT------------------------------------------------------------------------------
char* napis;
int dlugosc;
String(char* napis){
this->napis = new char[20];
//this->napis = napis;
memcpy(this->napis,napis,12);
this->dlugosc = this->length();
}
String(const String& obiekt){
int wrt = obiekt.dlugosc*sizeof(char);
//cout<<"before memcpy"<<endl;
this->napis = new char[wrt];
memcpy(this->napis,obiekt.napis,wrt);
//cout<<"after memcpy"<<endl;
this->dlugosc = wrt/sizeof(char);
}
~String(){
delete[] this->napis;
}
int length(){
int i = 0;
while(napis[i] != '\0'){
i++;
}
return i;
}
void show(){
cout<<napis<<" dlugosc = "<<dlugosc<<endl;
}
//THIS IS IMPORTANT
char & operator[](int el) {return napis[el];}
const char & operator[](int el) const {return napis[el];}
};
int main()
{
String* moj = new String("Alice has a cat");
cout<<(*moj)[2]; // IT WORKS BUI
// cout<<moj[2]; //I WOULD LIKE TO USE THIS ONE
return 0;
}
String* moj = new String("Alice has a cat");
cout<<(*moj)[2]; // IT WORKS BUI
// cout<<moj[2]; //I WOULD LIKE TO USE THIS ONE
That can't be done, the subscript operator in the later case is applied to a pointer. It is only possible to overload operators when at least one of the arguments is of user defined type (or a reference to it, but not a pointer); in this particular case the arguments are String* and 2, both fundamental types.
What you may do is drop the pointer altogether, I don't see why you need it:
String moj("Alice has a cat");
// cout<<(*moj)[2]; <-- now this doesn't work
cout<<moj[2]; // <-- but this does
String * means a pointer to a String, if you want to do anything with the String itself you have to dereference it with *moj. What you can do instead is this:
String moj = String("Alice has a cat"); // note lack of * and new
cout << moj[2];
Also note that anything you allocate with new needs to be deleted after:
String *x = new String("foo");
// code
delete x;