I have several questions about this particular piece of code. I should first mention that pChar will always be a dynamic character array that is resized when needed by methods I have not listed. I have scoured my reference manual and this website but cannot seem to gain a clear understanding of how the & operator works in full. I also do not want to use an alternative as this is an assignment and am not allowed to. I've been at this for days so any help would be appreciated.
What exactly is *this pointing to when using the & operator?
I have been assuming it points to the left operand.
If this is not the case, how do I access the left operand within the & operator method?
If this is all completely incorrect, how can I reach the desired outcome by using the overloaded operator&?
Method for & operator:
PDS_String & PDS_String::operator & (const PDS_String & Str)const
{
PDS_String temp(*this);
strcat(temp.pChar, Str.pChar);
return temp;
}
Main:
void main ()
{
PDS_String String1;
PDS_String String2;
PDS_String String3;
String1 = "monkey";
String2 = "chicken";
String3 = String1 & String2;
// Desired outcome for String3 is "monkeychicken"
}
Class:
class PDS_String
{
public:
PDS_String(); //Default
PDS_String(const PDS_String &); //Copy
~PDS_String(); //Destructor
char * operator & (const PDS_String &) const; // Concatenation
PDS_String & operator = (const char *); // Assignment
// I haven't listed all methods and operator overloads
private:
char * pChar;
long NumChars;
long NumSlots;
};
Assignment operator method:
PDS_String & PDS_String::operator = (const char * Str)
{
if (pChar == Str)
return *this;
else
{
if (NumSlots < strlen(Str))
{
delete[] pChar;
pChar = new char[(strlen(Str) + 1)];
NumSlots = (strlen(Str));
}
else;
}
strcpy(pChar, Str);
NumChars = strlen(Str);
return *this;
}
Thank you very much Matt McNabb. I have changed the operator& method to reflect your suggestion:
char * PDS_String::operator & (const PDS_String & Str)const
{
char * temp;
temp = new char[strlen(pChar)+strlen(Str.pChar)+1];
temp = pChar;
strcat(pChar, Str.pChar);
return temp;
}
*this refers to the left-hand operand. this points to the left-hand operand.
N/A
Stop returning a reference to a local object. temp ceases to exist when the function ends, so the caller has a dangling reference (causing undefined behaviour).
The normal semantics for a binary operator is to return an object by value. So you could change to PDS_String PDS_String::operator & (const PDS_String & Str)const and everything will be fine.
Usually what's done is that the operator+= function is a member function that changes *this, and then you have a free function X operator+(X x1, X x2) { return x1 += x2; }. You could do the same thing with operator& and operator&=.
You also have no protection against somebody trying to concatenate a long string and overflowing however much memory is allocated to pChar, you will need to add checks for that.
Related
I've been writing my own String class and I am not sure how to write operator+ correctly considering I could pass rvalues into it.I think I should have the following 3 non-member functions
String operator+(String &&lhs, String &&rhs);
String operator+(String& lhs,String&&rhs);
String operator+(String&&lhs,String&rhs);
However I am not sure how to implement them. Any help would be appreciated.
First, make sure to define copy and move constructors in your String class:
class String
{
private:
char *m_data;
std::size_t m_length;
...
public:
String();
String(const String &src);
String(String &&src);
~String();
...
};
String::String() :
m_data(nullptr),
m_length(0)
{
}
String(const String &src) :
m_data(new char[src.m_length+1]),
m_length(src.m_length)
{
std::copy_n(src.m_data, m_length, m_data);
m_data[m_length] = 0;
}
String(String &&src) :
m_data(nullptr),
m_length(0)
{
std::swap(m_data, src.m_data);
std::swap(m_length, src.m_length);
}
String::~String()
{
delete[] m_data;
}
Then define operator+ and operator+= for the class:
class String
{
public:
...
String& operator+=(const String &rhs);
...
friend String operator+(String lhs, const String &rhs)
{
lhs += rhs;
return lhs;
}
};
String& String::operator+=(const String &rhs)
{
String tmp;
tmp.m_length = m_length + rhs.m_length;
tmp.m_data = new char[tmp.m_length+1];
std:copy_n(m_data, m_length, tmp.m_data);
std:copy_n(rhs.m_data, rhs.m_length, tmp.m_data + m_length);
tmp.m_data[tmp.m_length] = 0;
std::swap(m_data, tmp.m_data);
std::swap(m_length, tmp.m_length);
return *this;
}
By taking a const String & as input on the right side, that will handle both lvalue and rvalue inputs.
For operator+, the left-hand side is taken by value so the compiler can decide the best constructor to use based on whether the input is an lvalue (copy) or rvalue (move).
Alternatively, you can implement it to take const String & on the left side so it still handles lvalues and rvalues, but then you have to implement it similar to how operator+= is implemented to avoid the extra allocation of copying lhs before concatenating onto it:
friend String operator+(const String &lhs, const String &rhs)
{
/*
String tmp(lhs);
tmp += rhs;
return tmp;
*/
String tmp;
tmp.m_length = lhs.m_length + rhs.m_length;
tmp.m_data = new char[tmp.m_length+1];
std:copy_n(lhs.m_data, lhs.m_length, tmp.m_data);
std:copy_n(rhs.m_data, rhs.m_length, tmp.m_data + lhs.m_length);
tmp.m_data[tmp.m_length] = 0;
return tmp;
}
Either way, you should also define a conversion constructor and operator+ for const char * input as well:
class String
{
public:
...
String(const char *src);
...
friend String operator+(const char *lhs, const String &rhs)
{
return String(lhs) + rhs;
/* or:
std::size_t len = std::strlen(lhs);
String tmp;
tmp.m_length = len + rhs.m_length;
tmp.m_data = new char[tmp.m_length+1];
std:copy_n(lhs, len, tmp.m_data);
std:copy_n(rhs.m_data, rhs.m_length, tmp.m_data + len);
tmp.m_data[tmp.m_length] = 0;
return tmp;
*/
}
...
};
String::String(const char *src) :
m_data(nullptr),
m_length(std::strlen(src))
{
m_data = new char[m_length+1];
std::copy_n(src, m_length, m_data);
m_data[m_length] = 0;
}
This will allow concatenating String objects with string literals (String + "literal", "literal" + String, String += "literal", etc).
See operator overloading on cppreference.com for more details.
The way I usually do it is like this:
class foo
{
...
public:
...
foo&& operator +(foo const & other) &&;
foo&& operator +(foo && other) const &;
foo&& operator +(foo && other) &&;
foo operator +(foo const & other) const &;
};
Not sure if Microsoft supports this but this is a good way to do this in more recent standards. Try clang if msvc wont let you.
The advantages of doing it this way are that you get very fine levels of control over the method used. These 4 operations can also be defined outside of the class if needed. But you'll always want 4 for the 4 possibilities of r-value/l-value combinations.
Also, you generally want to qualify l-values as const to indicate that they are not modified.
Simply defining a copy/move constructor is not usually an efficient solution to this problem. You will need a good understanding of how rvalue references work to implement this efficiently.
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.
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.
I want to create a bigInteger class that uses arrays in backend.
BigInt a = 4321; // assume in BigInt class: array is {4,3,2,1}
BigInt b = 2131; // assume in BignInt class: array is {2,1,3,1}
BigInt sum = a + b; // array {6,4,5,1}
I wrote this function to overload '+' operator to add the two numbers
int* operator+(const uint32& other) const{
uint32 sum[n];
for(int i=0; i<n; i++){
sum[i] = (*this[i]) + other[i];
}
return sum;
}
but it doesn't work.
Note: assume the array size to be fixed.
My question was not answered in Overload operator '+' to add two arrays in C++ and I made more clarification on this question.
Thank you
The immediate problem is that you're returning a pointer to an automatic (i.e. function-local) variable. The variable goes out of scope the moment the function returns. Dereferencing the returned pointer would lead to undefined behaviour.
I would argue that the method's signature should look like this:
class BigInt {
BigInt operator+(const BigInt& other) const {...}
...
}
In other words, it should take a reference to an instance of BigInt and should return another instance of BigInt (by value).
// friend_artih_op.cpp (cX) 2014 adolfo.dimare#gmail.com
// http://stackoverflow.com/questions/27645319/
/*
I like arithmetic operators to be 'friend' functions instead of 'class
members' because the compiler will automatically insert invocations to
construct a class value from literals, as it happens inside the
'assert()' invocations in this program.
*/
/// A small 'fake' arithmetic class
class arith {
private:
long * m_ptr; ///< pointed value
public:
arith( long val=0 )
{ m_ptr = new long; *m_ptr = val; }; ///< Default constructor.
arith( const arith& o )
{ m_ptr = new long;
*m_ptr = *(o.m_ptr); } ///< Copy constructor.
~arith( ) { if (0!=m_ptr) { delete m_ptr; } } ///< Destructor.
// operator long() const { return *m_ptr; } ///< Get stored value.
long to_long() const { return *m_ptr; } ///< Get stored value.
friend arith operator+( const arith left , const arith right );
friend bool operator==( const arith left , const arith right );
};
inline arith operator+( const arith left , const arith right ) {
long res = *(left.m_ptr) + *(right.m_ptr);
// 'new long' will be called within the copy constructor
return arith( res );
} ///< letf+rigth
inline bool operator==( const arith left , const arith right ) {
return ( *(left.m_ptr) + *(right.m_ptr) );
} ///< letf==rigth ???
#include <cassert> // assert()
int main() {
arith four(4);
assert( arith(6) == 2+four ); // 2 gets converted to arith(2)
assert( (6) == (2+four).to_long() );
// If you make 'operator+()' a member function, you would not have the
// compiler do the conversion (and you have to do it yourself):
assert( arith(6) == arith(2)+four );
}
// EOF: friend_artih_op.cpp
I have a test class of my to make my own string functions. I have a problem with the copy destructor.
I have 2 strings: s1 and s2.
I call the function s3 = s1 + s2;
It first calls the operator+ function and when it's finished it calls the destructor. Because of this the string object in the operator= function is empty. How can I fix this?
Destructor:
String::~String() {
if (this->str)
delete[] str;
str = NULL;
len = 0;
}
Copy Constructor:
String::String(const String& string) {
this->len = string.len;
if(string.str) {
this->str = new char[string.len+1];
strcpy(this->str,string.str);
} else {
this->str = 0;
}
}
operator=:
String & String::operator= (const String& string) {
if(this == & string)
return *this;
delete [] str;
this->len = string.len;
if(string.str) {
this->str = new char[this->len];
strcpy(this->str,string.str);
} else {
this->str = 0;
}
return *this;
}
operator+:
String& operator+(const String& string1 ,const String& string2)
{
String s;
s.len = string1.len + string2.len;
s.str = new char[string1.len + string2.len+1];
strcpy(s.str,string1.str);
strcat(s.str,string2.str);
return s;
}
operator+ should not return a local variable by reference.
Change the return type of operator+ to String. Ie, make the signature:
String operator+( String const& lhs, String const& rhs )
You probably also want to write a "move constructor" for your String class: String( String&& other ) if you are writing your code in C++11.
A simple move constructor:
String::String( String&& other ): len(other.len), str(other.str) {
other.len = 0;
other.str = nullptr;
}
This isn't required, because the copy in the return statement of your operator+ will probably be "elided" by your compiler under non-trivial optimization levels, but still good practice.
It's calling the Destructor because String s is going out of scope in your operator+ overload. Your operator+ overload needs to be returning a copy instead of a reference.
Therefore you should change your operator+ to
String operator+(const String& string1, const String& string2)
Yeah i got your problem
The thing is when you are returning a reference to a temp object from + operator function and then you are assigning this to other object in main So here = overloaded function gets called in to which you are passing a reference to an object that no longer exists
So either you can return a copy from + operator function
or
you can pass a copy in the = overlaoded function