Let me tell you guys I am beginner to c++.
For educational and learning purpose I have created my own string class named MyString. As per instructions from my instructor I am not allowed to use standard library functions to compare two strings.
MyString class contains char type pointer and integer type variable that holds length of string i.e:
class MyString{
char *str; int len;
public:
MyString(){
len = 1;
str = new char[len];
str[len - 1] = '\0';
}
MyString(char *p){
int count = 0;
for (int i = 0; p[i] != '\0'; i++){
count++;
}
len = count;
str = new char[len];
for (int i = 0; i < len; i++){
str[i] = p[i];
}
}
int length(){
return len;
}
bool operator < (MyString obj){
char temp;
if (len < obj.len){ return true; }
if (len>obj.len){ return false; }
if (this->len == obj.len){
for (int i = 0; i < len; i++){
if (this->str[i] < obj.str[i])
{
return true;
}
}
}
}
bool operator > (MyString obj) {
if (len > obj.len) {
return true;
}
if (len<obj.len) {
return false;
}
if (this->len == obj.len)
{
for (int i = 0; i < this->len; i++) {
if (this->str[i] > obj.str[i]) {
return true;
}
}
}
}
bool operator == (MyString obj) {
int count = 0;
if (this->len == obj.len){
for (int i = 0; i < this->len; i++) {
if (this->str[i] == obj.str[i]) {
count++;
}
}
if (count == len) {
return true;
}
}
}
char & operator[](int i) {
return str[i];
}
};
Here is main
int main()
{
char arr1[30], arr2[30];
cout << "Enter first MyString: ";
cin.get(arr1, 30);
cin.ignore();
cout << "Enter second MyString: ";
cin.get(arr2, 30);
MyString s1(arr1); //parametrized constructor
MyString s2(arr2);
cout << "Length of s1:" << s1.length() << endl;
cout << "Length of s2:" << s2.length() << endl;
if (s1<s2) // < operator overloaded
cout << "s1 < s2" << endl;
else if (s1>s2) // > operator overloaded
cout << "s1 > s2" << endl;
else if (s1 == s2) // == operator overloaded
cout << "s1 == s2" << endl;
return 0;
}
My algo for comparing two strings is:
i).First check length of two strings if len(length of s1) is less than obj.len(length of s2) than it returns true.
ii).if lengths are equal, compare for each element of s1 char array with s2 char array.Even if one of element of s1 char array is less than that s2 char array element (in ASCII) than return true otherwise return false.
The problems is whenever program executes, on console it shows "s1< s2" no matter if two strings passed are equal .
You're trying to write simple classes that allocate resources. This is a very important skill to have. What you've written so far has some good code, but also a lot of mistakes. The main errors are
Wrong algorithm for operator<. In your code "hello" < "goodbye" which is incorrect
Missing return statements.
Lack of destructor, so your class leaks memory.
Once you add a destructor you will also need a copy constructor and copy assignment operator otherwise your code will crash by freeing the same memory twice, this is known as the rule of three. Google it as it's perhaps the most important piece of C++ advice you'll read.
Lack of awareness of const correctness.
Lack of awareness of pass by reference.
Less than ideal signatures for your overloaded operators.
Missing some important methods on your class
Missing a few implementation tricks.
Putting all that together here an implementation of your class following the rules you've been given, with a few comments as well
class MyString {
char *str; int len;
public:
// default constructor should create a empty string, i.e. a zero length string
MyString() {
len = 0;
str = new char[len];
}
// contents of p are not changed so make it const
MyString(const char *p) {
int count = 0;
for (int i = 0; p[i] != '\0'; i++){
count++;
}
len = count;
str = new char[len];
for (int i = 0; i < len; i++){
str[i] = p[i];
}
}
// destructor, frees memory
~MyString() {
delete[] str;
}
// copy constructor, similar to the above except it starts from a MyString
MyString(const MyString& o) {
len = o.len;
str = new char[len];
for (int i = 0; i < len; i++){
str[i] = o.str[i];
}
}
// swap method, efficient exchange of two strings
void swap(MyString& o)
{
int t1 = o.len;
o.len = len;
len = t1;
char* t2 = o.str;
o.str = str;
str = t2;
}
// assignment operator, uses copy and swap idiom
MyString& operator=(MyString o) {
swap(o);
return *this;
}
// length does not modify the string, so it should be decalred const
int length() const {
return len;
}
char& operator[](int i) {
return str[i];
}
// need a const version of operator[] as well, otherwise you won't be able to do [] on a const string
char operator[](int i) const {
return str[i];
}
};
// operator< should be a function not a class method. This is the only way to get
// C++ to treat the two arguments symmetrically. For instance with your version
// "abc" < str is not legal, but str < "abc" is. This oddity is because C++ will
// not implicitly create a MyString object to call a MyString method but it will implicitly
// create a MyString object to pass a parameter. So if operator< is a function you will
// get implicit creation of MyString objects on either side and both "abc" < str and
// str < "abc" are legal.
// You also should pass to parameters by const reference to avoid unnecessary
// copying of MyString objects.
// Finally this uses the conventional algorithm for operator<
bool operator<(const MyString& lhs, const MyString& rhs) {
for (int i = 0; ; ++i)
{
if (i == rhs.length())
return false;
if (i == lhs.length())
return true;
if (lhs[i] > rhs[i])
return false;
if (lhs[i] < rhs[i])
return true;
}
}
// This is the easy way to write operator>
bool operator>(const MyString& lhs, const MyString& rhs) {
return rhs < lhs;
}
// This is the easy way to write operator<=
bool operator<=(const MyString& lhs, const MyString& rhs) {
return !(rhs < lhs);
}
// This is the easy way to write operator>=
bool operator>=(const MyString& lhs, const MyString& rhs) {
return !(lhs < rhs);
}
// operator== is a function not a method for exactly the same reasons as operator<
bool operator==(const MyString& lhs, const MyString& rhs) {
if (lhs.length() != rhs.length())
return false;
for (int i = 0; i < lhs.length(); ++i)
if (lhs[i] != rhs[i])
return false;
return true;
}
// this is the easy way to write operator!=
bool operator!=(const MyString& lhs, const MyString& rhs) {
return !(lhs == rhs);
}
There are countless issues with your code, so I'll provide an improved, commented implementation for you:
class MyString
{
char* str;
unsigned int len; // strings can't have negative length; using unsigned reflects this better
// even better: use size_t; this is the type for the concrete system
// able to cover any allocatable memory size
public:
MyString()
: str(new char[1]), len(1) // prefer initializer list
{
str[0] = 0; // does not matter if you use 0 or '\0', just my personal preference...
}
MyString(char const* p)
// you make a copy of, so have a const pointer (you can pass both const and non-const to)
{
for(len = 1; p[len] != 0; ++len);
// ^ make sure to copy the terminating null character as well!
str = new char[len];
for (unsigned int i = 0; i < len; i++)
{
str[i] = p[i];
}
// or use memcpy, if allowed
}
// OK, above, you allocated memory, so you need to free it again:
~MyString() // if you want to be able to inherit from, it should be virtual;
// strings, though, most likely should not be inherited from...
{
delete[] str;
}
// C++ creates a default copy constructor; this one, however, just copies all members by value
// i. e. copies the POINTER str, but not the memory pointed to, i. e. does not perform a deep copy
// which is what you need, however, to avoid double deletion:
MyString(MyString const& other)
: str(new char[other.len]), len(other.len)
{
for (unsigned int i = 0; i < len; i++)
{
str[i] = other.str[i];
}
}
// similar for assignment; I'm using copy and swap idiom to reduce code duplication here:
MyString& operator=(MyString other)
{
swap(other);
return *this;
}
void swap(MyString& other)
{
char* str = this->str;
unsigned int len = this->len;
this->str = other.str;
this->len = other.len;
other.str = str;
other.len = len;
}
unsigned int length() const
// ^^^^^ allows to retrieve length from a
// const MyString as well!
{
return len;
}
// fine, you can change the character within the string
char& operator[](unsigned int i)
{
return str[i];
}
// but what, if you have a const MyString???
// solution:
char operator[](unsigned int i) const
// ^^^^^
{
return str[i];
}
// you could alternatively return a const reference,
// but char is just too small that a reference would be worth the effort
// additionally: a reference could have the const casted away by user
// which is not possible by returning a copy, so we gain a little of safety as well...
bool operator<(MyString const& other) const
// ^^^^^^
// we don't need a copy and don't want a copy(it would just costs runtime and memory for nothing)!
// -> pass by const reference
// additionally, we want to be able to do comparison on const this as well (see length)
//
{
// have you noticed that you have one and the same code in all of your comparison operators???
// only the comparison itself changes lets have it just a little bit cleverer:
return compare(other) < 0;
}
bool operator>(MyString const& other) const
{
return compare(other) > 0;
}
bool operator==(MyString const& other) const
{
return compare(other) == 0;
}
// and for completeness:
bool operator<=(MyString const& other) const
{
return compare(other) <= 0;
}
bool operator>=(MyString const& other) const
{
return compare(other) >= 0;
}
bool operator!=(MyString const& other) const
{
return compare(other) != 0;
}
// the upcoming space ship operator (<=>) will simplify this, well, OK, but for now, we don't have it yet...
int compare(MyString const& other) const
{
// I decided to compare "abcd" smaller than "xyz" intentionally
// for demonstration purposes; just place your length checks
// back to get your original comparison again
unsigned int pos = 0;
// EDIT: "stealing" john's implementation, as superior to
// mine (with minor adaptions) ...
for (unsigned int pos = 0; ; ++pos)
{
///////////////////////////////////////////////////
// if you have your original length checks placed back above,
// just have the following check instead of the active one:
// if(pos == len) return 0;
if (pos == len)
{
return pos == other.len ? 0 : -pos - 1;
}
if (pos == other.len)
{
return pos + 1;
}
///////////////////////////////////////////////////
if(str[pos] < other.str[pos])
{
return -pos - 1;
}
if(str[pos] > other.str[pos])
{
return pos + 1;
}
}
return 0;
}
// WARNING: above code has yet an issue! I wanted to allow (for demonstration)
// to return positional information so that we not only see the result of comparison
// but can conclude to at WHERE the two strings differ (but need 1-based offset for to
// distinguish from equality, thus addition/subtraction of 1);
// however, on VERY large strings (longer than std::numeric_limits<int>::max()/-[...]::min()), we get
// signed integer overflow on the implicit cast, which is undefined behaviour
// you might want to check against the limits and in case of overflow, just return the limits
// (leaving this to you...)
// alternative: just return -1, 0, +1, the issue is gone as well...
};
OK, you now could just copy this code, strip the comments and present it as "your" solution. This is not what I intended this answer for! Take your time and read my comments carefully – you can learn quite a bit from...
Finally: there is yet another improvement possible: Before C++11, you could only copy data, if passing objects by value. Since C++, we additionally can move data from one object into another one – however, the type needs to support move semantics. You can do so by additionally providing a move constructor and copy assignment:
MyString(MyString&& other)
: str(nullptr), len(0)
{
// delete[]'ing nullptr (in other!) is OK, so we don't need
// to add a check to destructor and just can swap again...
swap(other);
}
MyString& operator=(MyString&& other)
{
// and AGAIN, we just can swap;
// whatever this contained, other will clean it up...
swap(other);
return *this;
}
You might be interested in further reading:
rule of three
rule of five
copy and swap idiom
In your function,
bool operator < (MyString obj){
I see no way to return false at the end!
It only returns true if it reach the 3rd if.
In addition, as others mentioned, the length does not imply the comparison in the way that you implemented.
Just a comment: Your code is prone to memory leak. It allocates but does not release the memory.
This code has lots of mistakes:
No copy constructor and copy is created
Missing destructor saves the day (memory leak, but thanks to that you do not have a crash for point 1)
len = 1 for empty string (default constructor).
MyString(char *p) do not add terminating character
not using const MyString &obj (unneeded copies).
missing return values at the end of various branches of methods
bool operator < (const MyString &obj) {
if (len < obj.len) {
return true;
}
if (len>obj.len) {
return false;
}
for (int i = 0; i < len; i++) {
if (this->str[i] != obj.str[i]) {
return this->str[i] < obj.str[i];
}
}
return false;
}
Related
[NOTE: My first attempt to implement such class, so please, don't throw stones at me and please don't be rude. Be patient. Thanks.]
So, I have written a custom MyString Class in C++.
Running version can be found here: https://onlinegdb.com/rJMEzP9aD.
I got some strange behaviors. I am trying to get the copy constructors, copy operator and the const char* data() to work together.
EDIT #4: This is strange,
class MyString {
public:
MyString(): pSize{0}, pStr{nullptr} {}
MyString(const char* cstr):
pSize{compute_length(cstr)}, pStr{nullptr}
{
pStr = new char[pCapacity];
std::copy(cstr, cstr + pSize, pStr);
}
MyString(const MyString& rhs):
pSize{rhs.size()}, pStr{nullptr}
{
pStr = new char[pCapacity];
std::copy(rhs.data(), rhs.data() + rhs.size(), pStr);
}
~MyString()
{
if(pStr){
delete[] pStr;
}
}
size_t size() const { return pSize; }
size_t capacity() const { return pCapacity; }
const char* data() const { return pStr; }
MyString& operator=(const MyString& rhs){
if(this == &rhs)
return *this;
if(pCapacity < rhs.size()){
delete[] pStr;
pSize = rhs.pSize;
pCapacity = (pCapacity < rhs.capacity()) ? rhs.capacity() : pCapacity;
pStr = new char[pCapacity];
std::copy(rhs.data(), rhs.data() + rhs.size(), pStr);
return *this;
}
pSize = rhs.size();
pCapacity = rhs.capacity();
std::copy(rhs.data(), rhs.data() + rhs.size(), pStr);
return *this;
}
private:
size_t pSize;
char* pStr;
size_t pCapacity = 14;
inline size_t compute_length(const char* cstr)
{
if(cstr == "")
return 0;
size_t i = 0;
while(cstr[++i] != '\0');
return i;
}
}
Main.cpp,
int main()
{
MyString s("Hello");
//assert(s == "Hello");
cout << s << endl;
s = "";
cout << s << endl;
assert(s == "wow");
return 0;
}
This class supports what a regular String class supports, NOT everything, and obviously far from perfect. However, there's a const char* data() const; which returns a pointer. So, in case the previous class modifies the content of its pointer, the other pointer must also be affected. Like the STD class does. However, for my implementation this comes with some cost. Here I have no idea currently why I have the issues I have. For example: performing s = "something new";, doesn't seem to replace previous. Or, copy/move to previous allocated memory pointer e.g. when sizes of a string and local heap allocated string match vice versa.
compute_length function would return 1 when used on an empty string (try to increment iinside the loop).
Try to write your operators and constructors for char* not only for MyString
The == operators seem not to be complete.
I didn't read the code in detail, so I may have missed important stuff.
Some changes
Always store the string null terminated. It'll help interacting with other APIs.
Two friends added for std::ostream and ==.
Memory cleanup.
Capacity always set to largest allocation seen during the class lifetime.
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
class MyString {
public:
MyString() : MyString(""){}
MyString(const char* cstr):
pSize{compute_length(cstr)}, pStr{new char[pSize+1]}, pCapacity{pSize}
{
std::copy_n(cstr, pSize + 1, pStr);
}
MyString(const MyString& rhs):
pSize{rhs.size()}, pStr{new char[pSize+1]}, pCapacity{pSize}
{
std::copy_n(rhs.data(), rhs.size()+1, pStr);
}
~MyString()
{
delete[] pStr;
}
size_t size() const noexcept{ return pSize; }
size_t capacity() const noexcept{ return pCapacity; }
const char* data() const noexcept{ return pStr; }
char* data() noexcept { return pStr; }
MyString& operator=(const MyString& rhs){
if(this == &rhs)
return *this;
pSize = rhs.size();
if(pCapacity < rhs.size()){
delete[] pStr;
pStr = nullptr;
pStr = new char[pSize+1];
pCapacity = pSize;
}
std::copy_n(rhs.data(), rhs.size() + 1, pStr);
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const MyString& string)
{
os.write(string.pStr, string.size());
return os;
}
friend bool operator==(const MyString& lhs, const MyString& rhs)
{
return std::strcmp(lhs.pStr, rhs.pStr) == 0;
}
private:
size_t pSize{};
char* pStr{};
size_t pCapacity{};
static inline size_t compute_length(const char* cstr)
{
size_t i = 0;
while(cstr[i] != '\0')++i;
return i;
}
};
int main()
{
using std::cout;
using std::endl;
MyString s("Hello");
assert(s == "Hello");
cout << s << endl;
s = "wow";
cout << s << endl;
assert(s == "wow");
return 0;
}
I have a problem with operator>> when I try to use it in my class String. I need to make a string from keyboard, but all my tries make fails. Help me, please.
When I try to turn in this code, I always have a crash.
#include<iostream>
#include<fstream>
using namespace std;
class myString
{
public:
friend std::ostream& operator<< (std::ostream& out, const myString& other);
friend std::istream& operator>> (std::istream& in, myString& other);
myString()
{
str = nullptr;
length = 0;
}
myString(const char* str)
{
length = strlen(str);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = str[i];
}
this->str[length] = '\0';
}
~myString()
{
delete[] this->str;
}
myString(const myString& other)
{
length = strlen(other.str);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = other.str[i];
}
this->str[length] = '\0';
}
myString& operator =(const myString& other)
{
if (this->str != nullptr)
{
delete[] str;
}
length = strlen(other.str);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = other.str[i];
}
this->str[length] = '\0';
return *this;
}
myString& operator =(const char* other)
{
if (this->str != nullptr)
{
delete[] str;
}
length = strlen(other);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = other[i];
}
this->str[length] = '\0';
return *this;
}
myString& operator +=(myString const& other) {
return (this->operator=(this->operator+(other)));
}
myString operator +(const myString& other)
{
myString newStr;
int thisLength = strlen(this->str);
int otherLength = strlen(other.str);
newStr.length = thisLength + otherLength;
newStr.str = new char[thisLength + otherLength + 1];
int i = 0;
for (; i < thisLength; i++)
{
newStr.str[i] = this->str[i];
}
for (int j = 0; j < otherLength; j++, i++)
{
newStr.str[i] = other.str[j];
}
newStr.str[thisLength + otherLength] = '\0';
return newStr;
}
void Print()
{
cout << str;
}
int Length()
{
return length;
}
bool operator ==(const myString& other)
{
if (this->length != other.length)
{
return false;
}
for (int i = 0; i < this->length; i++)
{
if (this->str[i] != other.str[i])
{
return false;
}
}
return true;
}
bool operator !=(const myString& other)
{
return !(this->operator==(other));
}
char& operator [](int index)
{
return this->str[index];
}
private:
char* str;
int length;
};
ostream& operator<< (ostream& out, const myString& other)
{
out << other.str;
return out;
}
istream& operator >> (istream& in, myString& other)
{
in.getline(other.str, sizeof(other.str));
return in;
}
int main()
{
myString str_3;
cin >> str_3;
cout << str_3;
return 0;
}
sizeof(other.str) is not the size of allocated buffer but the size of the pointer.
other.str is initialized to nullptr in the constructor, so it will try to read into invalid place and it will lead to Segmentation Fault.
Changing the constructor to
myString()
{
str = new char[1];
length = 0;
}
to keep the buffer size always length + 1 and changing the operator>> to
istream& operator >> (istream& in, myString& other)
{
in.getline(other.str, other.length + 1);
return in;
}
will prevent it from getting Segmentation Fault.
This won't solve the problem that the reading will be limited to length of already assigned string.
Improving the behavior will require other modifications like reading characters one-by-one and allocating buffer according to the size read.
You are trying to read to a pointer initialized with nullptr and you use sizeof() of that pointer when you have length data member. Since you already defined assignment operator for char array you can just use it:
istream& operator >> (istream& in, myString& other)
{
char buffer[256];
in.getline(buffer, sizeof(buffer));
other = buffer;
return in;
}
note buffer size is arbitrary here, real application should handle different sizes and grow on need, but that would require more advanced string implementation than yours. For your simplified solution which looks like student task this could be fine.
Note: your operator<< also has issue, if you call it on default constructed object it would lead to UB, as std::ostream does not accept nullptr on const char *. Simple check for nullptr would be sufficient there:
ostream& operator<< (ostream& out, const myString& other)
{
if(other.str)
out << other.str;
return out;
}
Ironically you did check for nullptr for delete[] which is not necessary.
You do not allocate space for your data member str in the default constructor. So when you write
myString str_3;
cin >> str_3;
then your code in operator>> (i.e. in.getline(other.str, sizeof(other.str));) will write to memory that you did not allocate before).
Make sure that str provides enough allocated memory before writing to it, e.g. by using alloc or realloc.
template <typename Object>
class Vector1 {
public:
explicit Vector1(const Object & value = Object()) : size_{0} {
array_ = new Object{value};
size_++;
}
Vector1(const Vector1 & rhs) : size_{rhs.size_} { //copy constructor
array_ = new Object[size_];
for (int i = 0; i < size_; i++) {
array_[i] = rhs.array_[i];
}
}
Vector1 & operator=(const Vector1 & rhs) { //copy assignment operator
array_ = new Object[rhs.size_];
if (this != &rhs) {
size_ = rhs.size_;
for (int i = 0; i < size_; i++) {
array_[i] = rhs.array_[i];
}
}
return *this;
}
Vector1(Vector1 && rhs) : array_{rhs.array_}, size_{rhs.size_} { //move constructor
rhs.array_ = nullptr;
rhs.size_ = 0;
}
Vector1 & operator=(Vector1 && rhs) { //move assignment operator
if (this != &rhs) {
std::swap(size_, rhs.size_);
std::swap(array_, rhs.array_);
}
return *this;
}
void print(ostream & out) const {
for (int i = 0; i < size_; i++) {
out << array_[i] << " ";
}
}
void ReadVector1() {
int count = 0;
cout << "Enter a size: ";
cin >> size_;
array_ = new Object[size_];
for (int i = 0; i < size_; i++) {
cout << "Enter element " << count + 1 << ": ";
cin >> array_[i];
count++;
}
}
size_t Size() const {
return size_;
}
**Vector1 operator+=(Vector1 & rhs) {
size_t combosize = size_ + rhs.size_;
Object combo[combosize];
int count = 0, rhscount = 0;
for (int i = 0; i < combosize; i++) {
if (i % 2 == 0) {
combo[i] = array_[count];
count++;
}
else {
combo[i] = rhs.array_[rhscount];
rhscount++;
}
}
std::swap(combosize, rhs.size_);
std::swap(combo, rhs.array_);
return *this;
}
Vector1 operator+(const Vector1 & rhs) const {
Vector1 temp(*this);
temp += rhs;
return temp;
}**
~Vector1() { //destructor
delete[] array_;
}
private:
size_t size_;
Object *array_;
};
template <typename Object>
ostream & operator<<(ostream & out, const Vector1<Object> & rhs) {
rhs.print(out);
return out;
}
int main(int argc, char **argv) {
Vector1<string> a, b;
a.ReadVector1(); //user provides input for Vector1 a
cout << a << endl;
b.ReadVector1(); //user provides input for Vector1 b
cout << b << endl;
cout << a + b << endl; //concatenates the two Vector1s
Vector1<string> d = a + b;
cout << d;
return 0;
}
The above is my code (thus far). What I'm trying to accomplish is to concatenate a's dynamic array with b's dynamic array (I cannot use vectors or any STLs, this is meant to be a rudimentary imitation of a vector).
Example:
The user inputs a size of 2 for a and inputs "Hello" and "World".
The user inputs a size of 2 for b and inputs "Goodbye" and "World".
The output should be "Hello World Goodbye World".
I highlighted what I think the problem is, which is the overloading of + and the += operators. My reasoning is that I create a new array, fill it up with the value's from a and b, swap the values, and then return the supposed concatenation.
My reasoning may not seem sound because frankly, I'm quite confused on how to proceed with this.
There are a few issues with your code concerning operator +=.
First, operator += should return a reference to the current object, i.e. return *this;. It shouldn't return a brand new Vector1 object.
Second, this line:
size_t combosize = size_ + rhs.size_;
Object combo[combosize];
is not valid ANSI C++, since arrays must be declared with a compile-time expression to denote the number of entries. Since combosize is a runtime value, it cannot be used.
You are probably using the GCC compiler, where there is a Variable Length Array extension, but again, this is an extension and is not really part of the C++ language.
Also, you are missing some constructors that would make writing operator += much easier. The constructor for Vector1 that you're lacking is this one:
Vector1::Vector1(size_t num) : array_(new Object[num]), size_(num) {}
This constructor just constructs a Vector1 with num entries.
Given the above, to fix the issues:
Vector1& operator+=(const Vector1 & rhs)
{
// create a temporary vector
Vector1 temp(size_ + rhs.size_);
// copy elements to temp array
for (int i = 0; i < size_; i++)
temp.array_[i] = array_[i];
// copy elements from rhs to temp array
int j = 0;
for (int i = size_; i < size_ + rhs.size_; i++, j++)
temp.array_[i] = rhs.array_[j];
// assign and return
*this = temp;
return *this;
}
Vector1 operator+(const Vector1 & rhs) const
{
Vector1 temp(*this);
temp += rhs;
return temp;
}
Note that in operator += we just create a temporary Vector1, fill it up with the values from *this and the passed in Vector1, and assign it to the current object. The *this = temp; line requires a working assignment operator. See the next section below.
The other issue is your Vector1::operator= is incorrect. It does not deallocate the memory allocated to _array previously, thus you have a memory leak.
The easiest way to fix this is to use the copy / swap you used in the operator=(Vector1 &&):
Vector1 & operator=(const Vector1 & rhs)
{
Vector1 temp(rhs);
std::swap(size_, temp.size_);
std::swap(array_, temp.array_);
return *this;
}
class SMTkrSym {
enum { SMTKRLEN = 16 };
uint8 data[SMTKRLEN];
public:
SMTkrSym() { memset(&data, 0, sizeof data); }
SMTkrSym(const char* pIn) { if (Read(pIn) < 0) memset(&data, 0, sizeof data); }
int16 Show(char* outstr) const; // display ticker symbol
int16 Read(const char* instr); // read ticker symbol
bool operator==(const SMTkrSym& rhs) const { return strncmp((char*)data, (char*)rhs.data, SMTKRLEN) == 0; }
bool operator!=(const SMTkrSym& rhs) const { return !(*this == rhs); }
bool operator>(const SMTkrSym& rhs) const { return (strncmp((char*)data, (char*)rhs.data, SMTKRLEN) > 0); }
bool operator<=(const SMTkrSym& rhs) const { return !(*this > rhs); }
bool operator<(const SMTkrSym& rhs) const { return (strncmp((char*)data, (char*)rhs.data, SMTKRLEN) < 0); }
bool operator>=(const SMTkrSym& rhs) const { return !(*this < rhs); }
};
unsigned int SMTkrSym::Read(const char* instr)
{
unsigned int i,j;
for (i = 0; (i < SMTKRLEN) && *instr; i++) // display until null
data[i] = *instr++;
for (j = i; j < SMTKRLEN; j++)
data[j] = '\0'; // null out rest of symbol
return i; // return actual number of characters
}
Usage of this class as below:
char pData[] = "helloworldyyyyyy";
char* p = pData;
SMTkrSym key1(p);
SMTkrSym key2;
key2 = key1;
The length of pData is equal to 16.
The SMTkrSym copy constructor will call read function and it will not put '\0' terminator character when the length of instr is larger or equal to 16.
My question is when program run key2 = key1 and does it will lead to crash?
When run key2 = key1 and it will call default assignment operator function.
But key1's data member variable doesn't include terminator character.
My concern is that if default assignment function uses strcpy function to
copy data member variable and it may lead to memory over flow.
I think if assignment function just look like memcpy(&key2, &key1,
sizeof(key1)), it won't crash. How does default assignment works?
The default compiler-provided operator= won't use strcpy() to copy data[]... it will safely copy all characters in the array, as if by memcpy as you say, though it may not actually use memcpy.
I need to do some logical comparison and return a boolean answer.
Here is the code from the .cpp file:
bool MyString::operator==(const MyString& other)const
{
if(other.Size == this.Size)
{
for(int i = 0; i < this.Size+1; i++)
{
if(this[i] == other[i])
return true;
}
}
else
return false;
}
Here is what is called from main.cpp file:
if (String1 == String4)
{
String3.Print ();
}
else
{
String4.Print ();
}
Here are there compiling errors I get:
error: request for member `Size` in `this`, which is of non-class type `const MyString* const`
error: no match for `operator[]` in `other[i]`
this is a pointer, hence you have to dereference it:
this->Size;
Also I think that logic of your operator== is flawed - here, it returns true if any of characters is equal to character on same position in second string. Change your loop to
for(int i = 0; i < this->Size+1; i++)
{
if(this[i] != other[i])
return false;
}
and put return true; instead of last part of your code (else clause) to compare entire strings.
As Seth mentioned, you can't use operator[] on this as above - this way it's treated as array (i.e. this[i] is really *(this + i) - so not what's you are thinking it is). Access your internal storage member instead.
Problems with your code:
this[i]: You apparently want to access the ith character of the string here. This isn't doing that. Assuming your class overloads operator[], you want (*this)[i]. Alternatively, you could directly access the internal representation of the string.
if(this[i] == other[i]) return true;: Think about what this means with respect to comparing the strings "A1" and "AB".
for () {...}: What happens when you exit the loop? You need to return something if the comparisons manage to make it through the loop without returning.
You haven't specified if you can use the C++ standard algorithms or not.
Here you have illustrated both versions, using hand-written loop and std::equal algorithm:
//#define USE_STD_ALGORITHM 1 // uncomment to enable std::equal version
#include <cassert>
#include <algorithm>
#include <stdexcept>
// NOTE: partial simplest definition for the test and presentation purposes only.
struct MyString
{
MyString(char const* s, std::size_t size) : data(s), Size(size) {}
char const& operator[](std::size_t index) const;
bool operator==(const MyString& other) const;
private:
char const* data;
std::size_t Size;
};
char const& MyString::operator[](std::size_t index) const
{
if (index < Size)
return data[index];
throw std::out_of_range("index invalid");
}
bool MyString::operator==(const MyString& other) const
{
if (this->Size == other.Size)
{
#ifdef USE_STD_ALGORITHM
return std::equal(data, data+Size, other.data);
#else
bool equal = true;
for(std::size_t i = 0; i < this->Size; ++i)
{
if((*this)[i] != other[i])
{
equal = false;
break;
}
}
return equal;
#endif
}
return false;
}
int main()
{
char const* a = "abc";
char const* b = "abc";
MyString sa(a, 3);
MyString sb(b, 3);
assert(sa == sb);
char const* c = "adc";
MyString sc(c, 3);
assert(!(sa == sc));
char const* d = "ab";
MyString sd(d, 2);
assert(!(sa == sd));
}
Good luck!