I need help figuring out how to overload the array operator for a MyString class that I have to create. I already have everything else figured out, but the arrays are giving me trouble, for some reason.
Here is my header file:
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
#include <cstring> // For string library functions
#include <cstdlib> // For exit() function
using namespace std;
// MyString class: An abstract data type for handling strings
class MyString
{
private:
char *str;
int len;
public:
// Default constructor.
MyString()
{
str = 0;
len = 0;
}
// Convert and copy constructors.
MyString(char *);
MyString(MyString &);
// Destructor.
~MyString()
{
if (len != 0)
delete [] str;
str = 0;
len = 0;
}
// Various member functions and operators.
int length() { return len; }
char *getValue() { return str; };
MyString operator+=(MyString &);
MyString operator+=(const char *);
MyString operator=(MyString &);
MyString operator=(const char *);
bool operator==(MyString &);
bool operator==(const char *);
bool operator!=(MyString &);
bool operator!=(const char *);
bool operator>(MyString &);
bool operator>(const char *);
bool operator<(MyString &);
bool operator<(const char *);
bool operator>=(MyString &);
bool operator>=(const char*);
bool operator<=(MyString &);
bool operator<=(const char *);
MyString operator [](MyString *);
// Overload insertion and extraction operators.
friend ostream &operator<<(ostream &, MyString &);
friend istream &operator>>(istream &, MyString &);
};
#endif
What would the body look like for MyString::operator []?
MyString MyString::operator [](MyString *)
{
... what goes here
}
The syntax for using the array operator with an object of the given class is:
MyString s("Test");
char c = s[0];
The argument to the function is an integral value.
Hence, the operator needs to be declared as:
// The non-const version allows you to change the
// content using the array operator.
char& operator [](size_t index);
// The nconst version allows you to just get the
// content using the array operator.
char operator [](size_t index) const;
MyString MyString::operator [](MyString *)
That's not how you should typically use a subscript operator.
What do you expect when you are using the [] operator? By the way you declared it, you are using a string pointer as argument, and receiving a string as return.
Usually, you pass an index type (commonly an unsigned-integer like size_t) and return the character at that position. If that's what you want, you should do something along these lines:
char& MyString::operator [](size_t position)
{
// some error handling
return str[position];
}
char MyString::operator [](size_t position) const { /* ... */ }
For overall guidelines on overloading operators, take a look at What are the basic rules and idioms for operator overloading?.
Also, I would point out that your destructor is a bit odd:
if (len != 0)
delete [] str;
str = 0;
len = 0;
Your indentation level suggests that you expect everything to happen inside the if statement, but only the first one will. That is not particularly dangerous in this case, because only the delete would suffice.
There is no problem in deleteing a null pointer, and str and len will be destroyed shortly after, so you don't have to bother resetting them.
Related
Here is my code:
class Mystring
{
private:
unsigned int size;
shared_ptr<char>message=make_shared<char>();
public:
Mystring(const char* input):size(strlen(input)),message(make_shared<char>(size+1))
{cout<<"Created"<<endl;memcpy(this->message,input,size+1);}
Mystring(const Mystring& other):size(other.size),message(make_shared<char>(size+1))
{cout<<"Created"<<endl;memcpy(this->message,other.message,size+1);}
~Mystring(){cout<<"Deleted"<<endl;}
friend ostream& operator<<(ostream& Cout,const Mystring& mystring)
{Cout<<mystring.message<<endl;return Cout;}
char& operator[](const unsigned int index)
{return this->message[index];}
};
I want to use smart pointers and operator [] properly. How can I solve these problems:
no suitable conversion function from "std::shared_ptr<char>" to "void *" exists
no operator "[]" matches these operands
So lots of problems with this code
You have a shared char array, so the type is shared_ptr<char[]> not shared_ptr<char>. This also means you cannot use make_shared, since it doesn't work with arrays.
If you want to access the pointer to the array use get().
Your copy constructor allocates a new array, which is a bit weird since why are you using shared_ptr, if you don't want to share the array? On the other hand the default assignment operator will share the array, so you have a strange situation where sometimes when you copy Mystring you will share the array, and sometimes you won't.
Various other minor issues
Here's a version that works
class Mystring
{
private:
size_t size;
shared_ptr<char[]> message;
public:
Mystring(const char* input) : size(strlen(input)), message(new char[size+1])
{
cout<<"Created"<<endl;
memcpy(message.get(), input, size+1);
}
Mystring(const Mystring& other): size(other.size), message(other.message)
{
cout<<"Created"<<endl;
}
~Mystring()
{
cout<<"Deleted"<<endl;
}
friend ostream& operator<<(ostream& Cout,const Mystring& mystring)
{
Cout<<mystring.message.get()<<endl;return Cout;
}
char& operator[](size_t index)
{
return message.get()[index];
}
};
I changed the copy constructor so that it does share the underlying array. You can change it back if you wish. However is you want a Mystring which does not share it's array with other Mystring objects then it would make more sense to use unique_ptr<char[]> instead of shared_ptr.
I have an assignment where I build my own my string class. I made several MYString objects and put them in a vector. When I access the vector through subscript operator, I have no issue. But when I traverse through the vector using foreach loop, then I get a weird error ""Pointer being freed was not allocated"
Did I mess up my copy constructor?
Is my destructor and clear() function messed up?
header file is as follows:
class MYString{
friend std::ostream& operator<<(std::ostream&, const MYString&);
friend std::istream& operator>>(std::istream&, MYString&);
private:
static const int INITIAL_CAP = 20;
char* str;
static int getLength(const char*);
int cap; //capacity of the char array, in multiples of 20
int end; // location of the null terminator
int compareTo(const MYString& rhs);
void clear(); // to manually free memory
static int requiredCap(int end);
public:
MYString();
MYString(const MYString& mystr);
MYString(const char*);
~MYString();
MYString& operator=(const MYString& rhs);
char& operator[](int index);
const char& operator[](int index) const;
int length() const;
int capacity() const;
const char* c_str();
MYString operator+(const MYString& rhs);
int operator==(const MYString& rhs);
int operator>(const MYString& rhs);
int operator<(const MYString& rhs);
};
Here is some relevant function defintions
MYString::MYString(const MYString& rhs){
*this = rhs;
}
MYString& MYString::operator=(const MYString& rhs){
if (this == &rhs){
return *this;
}
clear();
cap = rhs.cap;
end = rhs.end;
str = new char[cap];
for (int i = 0; i < end; i++){
str[i] = rhs[i];
}
str[end] = '\0';
return *this;
}
MYString::~MYString(){
clear();
}
void MYString::clear(){
cap = 0;
end = 0;
delete[] str;
str = nullptr;
}
The main method is as follows:
#include "MYString.h"
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main(){
ifstream input;
input.open("file.txt");
if (input.fail()){
cout << "File error" << endl;
}
MYString s;
vector<MYString> v;
int count = 0;
v.push_back(MYString());
int index = 0;
while (input >> s){
if (count == 2){
v.push_back(MYString());
count = 0;
index++;
}
if (count < 2){
v[index] = v[index] + s;
count++;
}
}
for (MYString& str : v){
cout << str << endl;
}
Serious problem with your constructor:
MYString::MYString(const MYString& rhs){
*this = rhs;
}
Inside the body of your object, your data is not initialized, but you dereference this and assign to it. The data members contain garbage, including the pointer. In the assignment operator, you call clear, which calls delete[] on this garbage pointer. This is undefined behavior.
Implementing a constructor in terms of assignment is always wrong. Assignment is for replacing state of an initialized object with new state, while constructors provide initial state to uninitialized members. The object's lifetime has not even started UNTIL the constructor completes. Calling functions on an object whose life has not officially started is undefined behavior.
Your copy constructor needs to allocate memory and copy the data into it, similar to what you did in your assignment operator, but not cleaning up the old state first. Also, consider using strcpy instead of a loop to copy bytes. It will be faster.
Just started learning C++ recently and I'm attempting to make my own string class from scratch. I'm currently working on concatenating strings by overloading += and + operators. After reading this article, basic-rules-of-operator-overloading, I have come up with the following implementation;
String & String::operator+=(const String &o)
{
char * newBuffer = new char[this->size() + o.size() - 1];
//copy over 'this' string to the new buffer
int index = 0;
while (this->at(index) != 0x0)
{
*(newBuffer + index) = this->at(index);
index++;
}
//copy over the param string into the buffer with the offset
//of the length of the string that's allready in the buffer
int secondIndex = 0;
while (o.at(secondIndex) != 0x0)
{
*(newBuffer + index + secondIndex) = o.at(secondIndex);
secondIndex++;
}
//include the trailing null
*(newBuffer + index + secondIndex) = 0x0;
//de-allocate the current string buffer and replace it with newBuffer
delete[] this->s;
this->s = newBuffer;
this->n = index + secondIndex;
return *this;
}
inline String operator+(String lhs, const String &rhs)
{
lhs += rhs;
return lhs;
}
However, the compiler will not recognise the + overload! It does work if I place the function in the main test file (where I am calling the method) but not if I place it in my String.cpp file where all my other methods are located.
Here is my String.h file if you need it;
#include <iostream>
class String
{
public:
String(const char * s);
String(const String &o);
int size() const;
char at(int i) const;
String &operator+=(const String &o);
private:
char * s;
int n;
//needs to be a friend function defined OUTSIDE of the class as when using
//ostream << String you do not have access to the ostream so they can't be
//member operators
friend std::ostream & operator<<(std::ostream &os, const String &o);
};
Thanks for any help!
(also, anything you think I can improve on in regards to my implementation would be graciously received)
Well everyone already explained, so it should be as simple as just adding the forward declaration to the end of your .h file like this:
#include <iostream>
class String
{
public:
String(const char * s);
String(const String &o);
int size() const;
char at(int i) const;
String &operator+=(const String &o);
private:
char * s;
int n;
//needs to be a friend function defined OUTSIDE of the class as when using
//ostream << String you do not have access to the ostream so they can't be
//member operators
friend std::ostream & operator<<(std::ostream &os, const String &o);
};
//forward declaration
String operator+(String lhs, const String &rhs);
The forward declaration just tells the compiler to look for a function with that signature. When it doesn't find it in your current .cpp file it looks up on the other .cpp files. I hope this helps!
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.
I'm doing an assignment for class in which I can't use the string class. I need to use char* as arrays and doing arithmetic with them.
My code being executed in main is the following: I create 2 myString objects and I add them. Then this is done correctly. Both strings get concatenated. but, there's a breakpoint at delete[] str. Can you tell me where I do wrong exactly? I'd like to understand what happens.
myString& myString :: operator+ (const myString& s)
{
myString tmp; //myString temporal
strcpy_s(tmp.str, strlen(str)+1,str); //STR is copied to tmp.str
Alloc(strlen(s.str)+size+1); //Then memory is allocated for both values
strcpy_s(str, strlen(tmp.str)+1, tmp.str); //WE COPY TMP.STR INTO STR NOW WITH ENOUGH SIZE FOR THE NEXT...
strcat_s(str, strlen(s.str) + size+1, s.str); //..ARGUMENT WE CONCATENATE 2 MYSTRING.STR
return (*this);
}
This is the class myString
class myString
{
public:
//Propietats
int size;
char* str;
//CONSTRUCTORS
myString();
myString(const myString&);
//myString(myString&);
myString(const char*, ...);
//Utilities
int Len(char*);
const void Clear();
const void Alloc(const int);
//Operators
bool operator== (const myString&) const;
bool operator== (const char* s) const;
const myString& operator= (myString&);
const myString& operator= (const char* s);
bool operator!= (const myString&) const;
bool operator!= (const char* s) const;
myString& operator+ (const myString&);
myString& operator+ (const char*);
//Metodes
~myString()
{
delete[] str; // **ERROR** THERE'S A BREAKPOINT HERE
}
};
#endif
My error is that there's a breakpoint in delete[] str; And I don't know what to do. It means there's an overflow? How do I solve it?
I'm quite new to pointer arithmetic so don't be harsh.
myString& myString :: operator+ (const myString& s)
{
myString tmp; //myString temporal
tmp.Alloc(strlen(str)+1); // Add this line
strcpy_s(tmp.str, strlen(str)+1,str); //STR is copied to tmp.str
...
You are not allocating room in tmp string. Once allocated, it should work fine.
You are probably corrupting the heap.
myString tmp;
What is tmp.str after this instruction ? Is tmp.str a NULL pointer ? A pointer to a buffer with some default size ?
strcpy_s(tmp.str, strlen(str)+1,str);
Did you make sure tmp.str has room for strlen(str)+1 char ?
You probably should call tmp.Alloc(strlen(str)+1) before this instruction.