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

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

Related

C++ does not use the desired constructor

So there seems to be some problem with the solution to Problem 9-2 in the book "Object-Oriented Programming in C++, 4th edition" by Robert Lafore. So the problem is that if I would like to create a Pstring object with a statement like Pstring = "This is a string", the Pstring constructor will only call the constructor with no arguments in the String class, instead of the second one with uses one char[] argument. Does anyone know what causes this kind of problem, and a fix to this? Thanks!
#include <iostream>
#include <cstring>
using namespace std;
////////////////////////////////////////////////////////////////
class String //base class
{
protected: //Note: can't be private
enum {
SZ = 80
}; //size of all String objects
char str[SZ]; //holds a C-string
public:
String() //constructor 0, no args
{
str[0] = '\0';
}
String(char s[]) //constructor 1, one arg
{
strcpy(str, s);
} // convert string to String
void display() const //display the String
{
cout << str;
}
operator char*() //conversion function
{
return str;
} //convert String to C-string
};
////////////////////////////////////////////////////////////////
class Pstring: public String //derived class
{
public:
Pstring(char s[]); //constructor
};
//--------------------------------------------------------------
Pstring::Pstring(char s[]) //constructor for Pstring
{
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
}
////////////////////////////////////////////////////////////////
int main() { //define String
String s1 = "This is a string"; // This works great
s1.display();
Pstring s2 = "This is a string"; // *** Here, nothing will be assigned to s2****
s2.display(); // *** Nothing will be printed here***
return 0;
}
In a function parameter, a T[] (where T is char in your case) is really a T*.
In C++, a string literal is a const char[N] fixed array, which decays into a const char* pointer to the 1st element. But you don't have any constructors that accept either of those types as a parameter. A const char* can't be given to a char*. You need to add const to your constructors:
String(const char s[])
Pstring(const char s[])
Also, calling String(s) in the body of the Pstring constructor does not initialize the Pstring object using the base class String constructor, like you are expecting. It instead constructs a temporary String object that goes out of scope immediately. The Pstring object is not affected by that.
The only place that a base class constructor can be called by a derived constructor is in the member initialization list. In your case, there is no such call, so the compiler implicitly calls the base class default (0-param) constructor before entering the body of the derived constructor. Which doesn't help you, since you want the base class to initialize the str buffer with data.
One way you can do that is add another constructor to String that takes a user-defined length as input, and then call that from the Pstring constructor, eg:
String(const char s[], size_t len)
{
len = std::min(len, SZ-1);
memcpy(str, s, len);
str[len] = '\0';
}
Pstring::Pstring(const char s[])
: String(s, strlen(s))
{
}
Note that your 1-param String constructor has a buffer overflow waiting to happen, since the user can directly construct a String object with input that is greater than SZ characters in length. The String constructor should use strncpy() instead of strcpy():
String(const char s[])
{
strncpy(str, s, SZ);
str[SZ-1] = '\0'; // in case s is >= SZ chars
}
Which then makes the 1-param Pstring constructor redundant - especially since it is not handling the null terminator correctly to begin with, as the assignment of the terminator needs to be outside of the for loop, eg:
Pstring::Pstring(const char s[])
{
if (strlen(s) >= SZ)
{
for (int j = 0; j < SZ - 1; j++) {
str[j] = s[j];
}
// alternatively: memcpy(str, sz, SZ-1);
str[SZ-1] = '\0'; // <-- moved here
}
else
strcpy(str, s);
}
In this conversion constructor
Pstring::Pstring(char s[]) //constructor for Pstring
{
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
}
at first the default constructor of the class String is called before the control will be passed to the constructor of the class Pstring.
So the data member is set like
String() //constructor 0, no args
{
str[0] = '\0';
}
As the argument that is the string literal "This is a string" that by the way as the argument has the type const char * due to the implicit conversion of arrays to pointers has the length that is less than SZ then within the body of the constructor Pstring nothing is done with the data member str. This statement
String(s);
creates a temporary object of the type String that is at once deleted.
What you need is to write at least
strcpy( str, s );
instead of creating the temporary object.
Pay attention to that the constructors with parameters shall be declared like
String( const char s[] );
and
Pstring( const char s[]);
if you are going to use string literals as arguments of the constructors.
You could move this code snippet
if (strlen(s) > SZ - 1) //if too long,
{
for (int j = 0; j < SZ - 1; j++) { //copy the first SZ-1
str[j] = s[j]; //characters "by hand"
str[j] = '\0';
} //add the null character
} else
//not too long,
String(s); //so construct normally
form the constructor Pstring to the constructor String with parameter and substitute it for one call of strncpy like
strncpy( str, s, SZ - 1 );
str[SZ-1] = '\0';
In C++, constructors aren't allowed to be called like this:
else
//not too long,
String(s);
C++ wants you to use its initialization list instead (see the link above for some examples).
If you have a portion of the construction in the parent class you would like to call from inside the child constructor, you can use a protected method instead:
class String //base class
{
protected:
void commonTask(char s[]) {
// do something...
}
public:
String(char s[])
{
commonTask(s);
}
};
class Pstring: public String
{
public:
Pstring(char s[]) { //constructor
if(someCondition) {
commonTask(s);
}
}
};
I'm using pseudo code here, but hopefully you get the idea.

What does Copy constructor do for dynamic allocations [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 7 years ago.
I am very curious why is copy constructor so important for the dynamic allocation of my own defined class.
I am implementing the low-level c-string class with dynamic allocations and here is a quick view of my class
class String
{
private:
char * buf;
bool inBounds( int i )
{
return i >= 0 && i < strlen(buf);
}
static int strlen(const char *src)
{
int count = 0;
while (*(src+count))
++count;
return count;
}
static char *strcpy(char *dest, const char *src)
{
char *p = dest;
while( (*p++ = *src++));
return dest;
}
static char* strdup(const char *src)
{
char * res = new_char_array(strlen(src)+1);
strcpy(res,src);
return res;
}
static char * new_char_array(int n_bytes)
{
return new char[n_bytes];
}
static void delete_char_array( char* p)
{
delete[] p;
}
public:
/// Both constructors should construct
/// this String from the parameter s
String( const char * s = "")
{
buf = strdup(s);
}
String( String & s)
{
buf = strdup(s.buf);
}
void reverse()
{
}
void print( ostream & out )
{
out << buf;
}
~String()
{
delete_char_array(buf);
}
};
ostream & operator << ( ostream & out, String str )
{
str.print(out);
return out;
}
I know the part of strdup() function is not really correct but I am just doing some tests.
My problem is if I do not have the copy constructor and my main() is
int main()
{
String b("abc");
String a(b);
cout << b << endl;
return 0;
}
The compiler will tell me double free or corruption (fasttop) and I find some answers about this question and see the Big three rules.
Can you guys tell me why my code works without any errors if I have the copy constructor and what the error of double free or corruption (fasttop) means?
If you don't define a copy constructor, the compiler will insert one for you. This default copy constructor will simply copy all the data members, so both instances of String will point to the same area of memory. The buf variable will hold the same value in each instance.
Therefore when the instances go out of scope and are destroyed, they will both attempt to release the same area of memory, and cause an error.

Storing a string as char[] with placement new and get it back

I want to write a Class which holds information about a string in Memory and which can give it back to me. So i started with a Union which holds the size of a string. (why union doesn't matter here but it need to be union for other types lateron) The constructor get a string passed and should put the string as c_str at the end of the Objekt which i place with placement new.
The class looks like this:
class PrimitivTyp
{
public:
explicit PrimitivTyp(const std::string &s);
std::shared_ptr<std::string> getString() const;
private:
union
{
long long m_long; //use long long for string size
double m_double;
} m_data;
ptrdiff_t m_next;
};
And the impl of the Ctor and the get function looks like this which doesnt work properly i guess.
PrimitivTyp::PrimitivTyp(const std::string& s)
{
m_data.m_long = s.size();
m_next = reinterpret_cast<ptrdiff_t>(nullptr);
//calc the start ptr
auto start = reinterpret_cast<ptrdiff_t*>(this + sizeof(PrimitivTyp));
memcpy(start, s.c_str(), s.size()); //cpy the string
}
std::shared_ptr<std::string> PrimitivTyp::getString() const
{
auto string = std::make_shared<std::string>();
//get the char array
auto start = reinterpret_cast<ptrdiff_t>(this + sizeof(PrimitivTyp)); //get the start point
auto size = m_data.m_long; //get the size
string->append(start, size);//appand it
return string;//return the shared_ptr as copy
}
The Usage should be something like this:
int main(int argc, char* argv[])
{
//checking type
char buffer[100];
PrimitivTyp* typ = new(&buffer[0]) PrimitivTyp("Testing a Type");
LOG_INFO << *typ->getString();
}
This crashes and i don't find the misstake with the Debugger. I think it is something with the position calculation of this.
this + sizeof(PrimitivTyp) is not what you think, you want this + 1 or reinterpret_cast<uint8_t*>(this) + sizeof(PrimitivTyp).
Pointer arithmetic in C and C++ takes into account the type of the pointer.
so with T* t;, (t + 1) is &t[1] (assuming non overload of operator &) or reinterpret_cast<T*>(reinterpret_cast<uint8_t>(t) + sizeof(T)).

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.

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;