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.
Related
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
The following code constitutes a MCVE, this reproduces the problem I want to ask about but it's not the real code. The real code is quite more complicated so that's why I wrote this for a demonstration of the problem.
The key feature I am looking for is to be able to grow a dynamically allocated array, please do not suggest using the stl because it's explicitly forbidden. This code is for educational purpose and thus there are restrictions.
#include <cstring>
#include <iostream>
class Value
{
public:
Value(int value = 0);
Value(const Value &value);
Value &operator =(const Value &other);
~Value();
operator int() {return *m_absurdPointer;}
private:
int *m_absurdPointer;
};
Value::Value(int value) :
m_absurdPointer(new int[1])
{
*m_absurdPointer = value;
}
Value::Value(const Value &value)
{
m_absurdPointer = new int[1];
memcpy(m_absurdPointer, value.m_absurdPointer, sizeof(*m_absurdPointer));
}
Value &Value::operator =(const Value &other)
{
m_absurdPointer = new int[1];
memcpy(m_absurdPointer, other.m_absurdPointer, sizeof(*m_absurdPointer));
return *this;
}
Value::~Value()
{
delete[] m_absurdPointer;
}
class ValueArray
{
public:
ValueArray();
~ValueArray();
void append(const Value &value);
void show() const;
private:
Value *m_array;
unsigned int m_capacity;
unsigned int m_length;
};
ValueArray::ValueArray() :
m_array(nullptr)
, m_capacity(0)
, m_length(0)
{
}
ValueArray::~ValueArray()
{
delete[] m_array;
}
void
ValueArray::append(const Value &value)
{
if (m_length >= m_capacity)
{
Value *newarray;
unsigned int unitSize;
unitSize = 1;
newarray = new Value[m_capacity + unitSize];
if ((m_capacity > 0) && (m_array != nullptr))
memcpy(newarray, m_array, m_capacity * sizeof(*m_array));
delete[] m_array;
m_array = newarray;
m_capacity += unitSize;
}
m_array[m_length++] = value;
}
void
ValueArray::show() const
{
for (size_t i = 0 ; i < m_length ; ++i)
std::cout << static_cast<int>(m_array[i]) << std::endl;
}
int
main(void)
{
ValueArray example;
for (int i = 0 ; i < 10 ; ++i)
example.append(Value(i));
example.show();
return 0;
}
It causes as you can see a double free issue, because the delete[] m_array; calls the destructor of the class Value after it has copied the values to the re-newed array.
I tried to do this with malloc()/realloc() but I need the destructor of Value() to be called so new is mandatory because I can't use free().
How to prevent this?, if I remove the delete[] m_absurdPointer; the double free would be gone of course but there would be a memory leak.
You basically want to implement an own vector class, right?
OK, first things first: As far as I know you cannot grow previously allocated memory. At least not with the standard allocator.
So you need to allocate a new, larger chunk of memory.
You can do this the standard way, using new:
Type * newdata = new Type[size];
In this case the constructor of the class Type will be called for each new element, which is size times.
To get your old data into that new array you need to copy or move it there:
for (size_t it = 0; it < oldsize; ++it) {
newdata[it] = olddata[it];
// newdata[it] = std::move(olddata[it]);
}
This is what std::copy resp. std::move are doing. (You could also use std::swap inside a loop.)
For that to work the Type class needs both a default constructor and a valid implementation of copy or move assignment.
You're using memcpy. In C++, this is generally a bad idea: Your implemented assignment operator isn't called, Therefore both the objects in your old array and the raw copies are using the same pointer, which is why you get that double free, obviously.
You could also allocate raw memory and use placement new to copy or move construct the new objects from the old ones:
void * memory = new char[size * sizeof(Type)];
for (size_t it = 0; it < oldsize; ++it) {
new (memory + it * sizeof(Type)) Type(olddata[it]); // copy
}
The above is only an example, for real code you need to consider alignment, too.
Finally, I'm sure you can somehow trick the default allocator to free your (old) memory without destructing the objects within, this allowing you to use the raw copy memcpy made. Though this would be a hack and could break on complex classes, it's not the C++ way of doing this.
The idiomatic way is to copy or move the old objects to the new storage (with either assignment or construction).
You should use the move-constructor if you have to stick with an vector-like implementation of ValueArray:
class Value
{
public:
Value(int value = 0);
Value(const Value &value);
Value(Value&& val);
Value &operator =(const Value &other);
Value &operator =(Value&& other);
~Value();
operator int() {return *m_absurdPointer;}
private:
int *m_absurdPointer;
};
Value::Value(Value&& o) : m_absurdPointer(o.m_absurdPointer) {
o.m_absurdPointer = nullptr;
}
Value &operator =(Value&& o) {
delete[] this->m_absurdPointer;
this->m_absurdPointer = o.m_absurdPointer;
o.m_absurdPointer = nullptr;
}
void
ValueArray::append(const Value &value)
{
if (m_length >= m_capacity)
{
Value *newarray;
unsigned int unitSize;
unitSize = 1;
newarray = new Value[m_capacity + unitSize];
if ((m_capacity > 0) && (m_array != nullptr)) {
std::move(m_array, m_array + m_length, newarray);
}
delete[] m_array;
m_array = newarray;
m_capacity += unitSize;
}
}
I am writing a operator function for - where my class object is a dynamic array of integer.
the operator takes lhs and rhs object and return an object which is the set of elements in lhs but not in rhs.
though I have written the function but I am not able to return the set since the destructor is called right after the object is returned.
IntegerSet & IntegerSet::operator - (IntegerSet & rhs) const
{
IntegerSet temp(capacity);//local object created to store the elements same size as lhs
int k=0;
int lhssize = ElementSize();//no. of elements in the set
int rhssize = rhs.ElementSize();
for (int i=0;i<lhssize;i++)
{
for (int j=0;j<rhssize;j++)
{
if (rhs.ptr[j]!=ptr[i])
{
k++;
}
}
if(k==rhssize)
{
temp = temp + ptr[i];
}
k=0;
}
return temp;
}
and here is the constructor if you cannot understand the object
IntegerSet::IntegerSet(const int & size)//works correctly
{
capacity = size;
ptr = new int [capacity]();
}
IntegerSet::IntegerSet(const int & size)//works correctly
{
capacity = size;
ptr = new int [capacity]();
}
IntegerSet::IntegerSet(const IntegerSet & copy) : capacity(copy.capacity)//works correctly
{
ptr = copy.clonemaker();
}
IntegerSet::~IntegerSet()
{
capacity = 0;
delete [] ptr;
}
int * IntegerSet::clonemaker() const // works correctly
{
if(ptr==NULL)
{
return NULL;
}
int *tempptr = new int [capacity];
for(int i=0;i<capacity;i++)
{
tempptr[i]=ptr[i];
}
return tempptr;
}
You'll have to return by value. The local object will be destroyed when the function returns, and there's no way to prevent that.
For that to work, your class will have to correctly follow the Rule of Three to make sure it's correctly copyable. In C++11 or later, you might also consider making it movable, to avoid unnecessary memory allocation and copying (although, in this case, the copy should be elided anyway).
Better still, follow the Rule of Zero and store a vector<int>, which will do all this for you, rather than trying to juggle raw pointers.
You need to change to return the result by value.
IntegerSet IntegerSet::operator - (IntegerSet & rhs) const
Also it would make more sense to supply rhs by const reference when taking a second look.
The code I have so far:
#include <iostream>
#include <vector>
using namespace std;
class Dictionary
{
private:
string dictName;
struct wordCard
{
string word;
string translation;
};
vector<wordCard> Dict;
bool foundit = false;
public:
// My attemtp at swap function for copy-and-swap:
void swap(Dictionary& dict1, Dictionary& dict2)
{
Dictionary dict3("tmp");
dict3.dictName = dict1.dictName;
dict3.Dict = dict1.Dict;
dict1.dictName = dict2.dictName;
dict1.Dict = dict2.Dict;
dict2.dictName = dict3.dictName;
dict2.Dict = dict3.Dict;
}
// Very basic constructor (setting the dictionary name while creating an object was part of the assignment):
Dictionary(string name)
{
setDictName(name);
}
/* various functions that work fine */
// Overloading "+" operator:
// The result is supposed to be a new dictionary (without changing the source) where all words from the
// original dictionaries are present without doubles.
Dictionary& operator+ (const Dictionary& dict)
{
bool doubleword = false;
string plusname;
plusname = "Augmenting " + this->dictName + " & " + dict.dictName;
Dictionary plusDict(plusname);
plusDict.Dict = this->Dict;
for (int i = 0; i < dict.Dict.size(); i++)
{
doubleword = false;
for (int i2 = 0; i2 < plusDict.Dict.size(); i2++)
{
if (plusDict.Dict[i2].word == dict.Dict[i].word)
{
doubleword = true;
}
}
if (!doubleword)
{
plusDict.Dict.push_back(dict.Dict[i]);
}
}
return *this;
}
/* 2 other overloads that are very similar */
// Overloading "=" operator (using copy-and-swap):
// Not part of the assignment, but I couldn't think of another way to make the other operators work.
Dictionary& operator=(Dictionary dict)
{
swap(*this, dict);
return *this;
}
};
And the problems I have with it:
Ideally, it should work like this:
Obj1 = result of operation Obj2 + Obj3;
What I'm getting at the moment is:
Obj1 = Obj2 (ignores Obj3)
I have a vague idea why it happens (or, actually, two ideas). First, operator+ returns *this, not the actual result. But when I tried to change it to the temp class object, compiler started screaming at me. Second, I'm aware that I'm using a local variable (temp class object), but I don't know how to make it public so I could use it later. When I try to add a class object to the public: section (or private:), the compiler treats it as a function declaration, not a class object.
So, how can I either make my temp class object public, or return result of a+b instead of *this, or make operator= catch the result or operator+ instead of what it returns?
operator + should return a new object by value and be const - i.e. something like
Dictionary operator+ (const Dictionary& dict) const
{
Dictionary ret;
//modify ret
return ret;
}
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;