When I'm using a pointer to an instance to this class, for some reason it crashes when it comes to the destructor. It works when I'm not using pointers
The weirdest part is that it works in VC Code but not in Visual Studio.
Polynomial.h
class Polynomial {
private:
int32_t* coeffs;
uint32_t deg;
public:
Polynomial(int32_t* setCoeffs, uint32_t setDeg) {
deg = setDeg;
while (setCoeffs[deg] == 0 && deg > 0) deg--;
coeffs = new int32_t[deg + 1]();
for (uint32_t i = 0; i <= deg; i++) {
coeffs[i] = setCoeffs[i];
}
}
~Polynomial () {
delete[] coeffs;
}
std::string str() {
std::string out = "";
for (uint32_t i = deg; i > 0; i--) {
if (coeffs[i] == 0) continue;
if (coeffs[i] > 0 && i != deg) out += "+";
if (coeffs[i] != 1)
out += std::to_string(coeffs[i]);
if (i == 1) out += "x";
else if (i > 1) out += "x^" + std::to_string(i);
}
if (coeffs[0] != 0) {
if (coeffs[0] > 0) out += "+";
out += std::to_string(coeffs[0]);
}
return out;
}
friend std::ostream& operator<<(std::ostream& out, Polynomial p) {
out << p.str();
return out;
}
};
main.cpp
#include <iostream>
#include "Polynomial.h"
int main(){
int32_t* coeffs = new int32_t[3]();
coeffs[0] = 5;
coeffs[1] = 4;
coeffs[2] = 3;
Polynomial* p = new Polynomial(coeffs, 2);
std::cout << (*p);
delete p;
return 0;
}
I'm guessing it's something to do with the Visual Studio properties but I don't know what to change.
Your overload of the << operator takes its argument by value; so, in the line, std::cout << (*p); a copy of *p is made and, when the output is done, that copy is destroyed. However, as pointed out in the comments, you haven't implemented a proper copy constructor, so the compiler provides a default, which simply copies the data members' values (including the int32_t* coeffs pointer member).
So, when the output operation is done, and the copy is destroyed, the memory pointed-to by coeffs is deleted; then, when you come to delete the original, you are trying to delete that same memory a second time – hence the crash.
To fix the issue either: (a) implement proper copy and assignment constructors, which make real copies of the coeffs data; or (b) give the argument to your << operator by reference, as follows:
friend std::ostream& operator<<(std::ostream& out, Polynomial& p) { // Pass "p" BY REFERENCE
out << p.str();
return out;
}
Of course, making the '(b)' change doesn't (shouldn't) mean that you can't also implement '(a)'. You should really do both; here's a likely implementation of the copy constuctor:
Polynomial(const Polynomial& rhs) {
deg = rhs.deg;
coeffs = new int32_t[deg + 1];
for (uint32_t i = 0; i <= deg; i++) {
coeffs[i] = rhs.coeffs[i];
}
}
Related
The goal I set to myself is to overload operator+ (adding class objects). It turns out that this sum can be just interpreted as the sum of two vectors. But when it comes to the method operator+, I find it difficult to return the object. I've read similar topics and even try to apply some sugestions but with no success, unfortunatelly. I enclose some of my code.
template<class Y>
class myVect {
public:
myVect(int n = 1);
~myVect();
myVect(const myVect& a);
myVect& operator= (const myVect&);
myVect& operator+ (const myVect&);
void display(const myVect& a);
private:
int size;
Y* data;
template<class U> friend class myClass;
};
template<class Y> // constructor
myVect<Y>::myVect(int n) {
size = n;
data = new Y[size];
cout << endl << "Pass the elements" << " " << size << "\n";
for (int i = 0; i < size; i++) {
cin >> *(data + i);
}
}
template <class Y> // deconstructor
myVect<Y> :: ~myVect() {
delete[] data;
}
template<class Y> // copy constructor
myVect<Y> ::myVect(const myVect & a) {
size = a.size;
data = new Y[size];
for (int i = 0; i < size; i++) {
*(data + i) = *(a.data + i);
}
}
template<class Y> //ASSIGMENT OPERATOR
myVect<Y> & myVect<Y> :: operator= (const myVect<Y> & a) {
if (this != &a) {
delete[] data;
size = a.size;
data = new Y[size];
for (int i = 0; i < size; i++) {
*(data + i) = *(a.data + i);
}
}
return *this;
}
The method operator+ is a follows:
template<class Y>
myVect<Y>& myVect<Y> ::operator+ (const myVect<Y>& a) {
if (this->size != a.size) {
cout << endl << "not able to perform that operation - wrong dimensions" << endl;
}
else {
myVect<Y> newObj(this->size);
for (int i = 0; i < this->size; i++) {
*(newObj.data + i) = *(this->data + i) + *(a.data + i);
}
}
return newObj;
}
The error I get is 'newObj': identifier not found. I believe it's due to deconstructor. I tried to put the class myVect into a new class (encapsulate it) and contruct the return method but it didn't change antything - the type of the error is still the same. Do you know how to solve this problem?
Anyway, if it is the destructor fault, does that mean that newObj is deleted before its return?
The problem can be reduced to this:
int foo()
{
if (true) // In reality, some meaningful condition
{
int x = 4;
}
return x;
}
The variable is scoped to the if block. It doesn't exist outside of it.
You'll have to move its declaration out of the conditional, and do whatever else is required to make that work… or return from inside the condition, and do something else (throw an exception?) otherwise.
For example, given the above demonstration:
int foo()
{
int x = 0; // Or some other value
if (true) // In reality, some meaningful condition
{
x = 4;
}
return x;
}
or:
int foo()
{
if (true) // In reality, some meaningful condition
{
int x = 4;
return x;
}
throw std::runtime_error("For some reason I have no value to give you!");
}
Your next problem will be that you are trying to return a local variable by reference. You cannot do that. Return it by value instead, which is anyway idiomatic for what you're doing.
You've declared your object inside of a block, so it won't exist in the outside scope. This would normally free you up to reuse variable names across different branches; try making a newObj inside the if part of the statement and watch it not throw an error, for example.
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;
}
I am practicing using templates and classes in C++. My goal is to write a template class for a deque. It will have functions to "insert_head", "insert_tail", "remove_tail", and "remove head", along with the ability to be printed using "cout". Also, the '=' operator must be able to be used to copy one instance of the class to another instance. Here is my current code:
#ifndef DEQUE_H
#define DEQUE_H
template <typename T>
class Deque {
public:
Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity)
{}
Deque(Deque & d) : x_(d.x()), size_(d.size()), capacity_(d.capacity()) {}
std::ostream & operator<<(std::ostream & cout) {
cout << '[';
if (size_ > 0) {
for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
std::cout << *(x_ + i) << ',';
}
cout << *(x_ + (size_ - 1)* sizeof(T));
}
cout << ']';
return cout;
}
Deque operator=(Deque d) {
Deque dq(d);
return dq;
}
void print_test() {
std::cout << '[';
if (size_ > 0) {
for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
std::cout << *(x_ + i) << ',';
}
std::cout << *(x_ + (size_ - 1)* sizeof(T));
}
std::cout << ']';
}
int * x() {
return x_;
}
int size() {
return size_;
}
int capacity() {
return capacity_;
}
bool is_empty() {
return size_ == 0;
}
void insert_tail(T tail) {
if (size_ < capacity_) {
*(x_ + sizeof(T) * size_) = tail;
size_++;
} else {
// throw overflow
}
}
T remove_tail() {
if (size_ > 0) {
T ret = *(x_ + sizeof(T) * (size_ - 1));
std::cout << ret;
size_--;
return ret;
} else {
// throw underflow
}
}
void insert_head(T head) {
if (size_ > 0 && size_ < capacity_) {
for (int i = (size_ - 1) * sizeof(T); i < 0; i -= sizeof(T)) {
*(x_ + i + sizeof(T)) = *(x_ + i);
}
}
if (size_ < capacity_) {
*x_ = head;
size_++;
} else {
// throw overflow
}
}
T remove_head() {
if (size_ > 0) {
T ret = *x_;
for (int i = sizeof(T); i < size_* sizeof(T); i += sizeof(T)) {
*(x_ + i - sizeof(T)) = *(x_ + i);
}
size_--;
return ret;
} else {
// throw underflow
}
}
private:
T * x_;
int size_;
int capacity_;
};
#endif
Here is my test code using that class:
#include <iostream>
#include "Deque.h"
int main(int argc, char const *argv[])
{
Deque< int > dq;
dq.insert_head(1);
// dq.insert_head(2); // adding head when not empty causes bug
dq.insert_tail(3);
dq.insert_tail(4);
dq.insert_tail(5);
dq.print_test(); std::cout << std::endl;
// std::cout << dq; // '<<' not overloaded properly'
std::cout << dq.remove_head() << " head removed\n";
// int x = dq.remove_head(); // seg faults when assigning returned value to a variable
dq.insert_tail(2);
dq.print_test();
std::cout << std::endl;
Deque< int > dq1(dq);
Deque< int > dq2;
// dq2 = dq1; // '=' not overloaded properly
return 0;
}
Each of my four problems is in a commented out line of code in my test file, here is a further explaination:
When "dq.insert_head(2)" is called and dq is not empty (size > 0) I try to shift all the other elements in the deque over one position so I can insert the new value there, there is a problem and the elements are not moved over.
"std::cout << dq" does not print dq like it should. The code is very similar to the "print_test()" method, however when I run the program I get the error "no match for operator <<". Is this because it is template class? Or am I doing something else completely wrong?
When trying to remove the head or tail from the deque, I am trying to return the value removed. In the line of code not commented out, the returned value is printed as it should, but the following line of code causes a seg fault. Is it because I'm trying to assign a template varabale to an integer variable?
My last issue is the '=' operator is not copying one instance of the class to another. My goal was to create a new instance of the class then return that instance (as you can see in the "Deque operator=(Deque d)") but that is not working as I hoped. What is the best way to overload the '=' function using template classes.
Thank you for your help, the answer to any of these questions is much appreciated.
All of your functions have issues:
Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity) {}
If you allows to specify a size, then you would have to allocate and initialize memory for those items. You should only specify capacity.
x_ is not initialized.
Assuming, you want a fixed capacity, then your constructor should be:
Deque(int capacity = 1000)
: size_(0)
, x_(new T[capacity])
, capacity_(capacity)
{
}
And even that is a simplified version as it would call the constructor for all items which might be inefficient and require that T has an accessible default constructor.
And now for the copy constructor:
The copy constructor should do deep copy. Otherwise, your program will (probably) crash after deleting the first Deque for which you have done copies as deleting an item twice is undefined behavior.
The prototype should take a constant reference as in: Deque(const Deque &other);
The code would look similar to this:
Deque(const Deque &other)
: capacity_(other.capacity_)
, x_(new T[other.capacity_])
, size_(other.size_)
{
for (int i = 0; i != size_; ++i)
{
x_[i] = other.x_[i];
}
}
For the <<, the prototype should be:
friend std::ostream & operator<<(std::ostream &cout, const T &data)
assuming it is declared inside the class to access private fields. You need to pass the data on which the operator works.
For the assignment operator, something like this could works:
Deque& operator=(const Deque &other)
{
// Use swap idiom...
Deque tmp(other);
// Swap pointers so old x_ get destroyed...
T *old_x = x_;
x_ = tmp.x_;
tmp.x_ = old_x;
// Usually one would use std::swap.
// Here as tmp get destroyed, it is not strictly to swap capacity_ and size_.
capacity_ = tmp.capacity_;
size_ = tmp.size_;
}
Now for the x() function:
- If you do a queue, you probably don't want to expose data so the function should be removed.
- If it was kept, the function should be const and returns a pointer to T: T *x() const; for the expected functionality.
size, capacity and is_empty should all be const member functions.
insert_tail and remove_tail problems have been explain in other people comments (in particular extraneous sizeof).
Similar problems for insert_head and remove_head also. In addition, the code that copy existing items could be refactored inside a private function to follows the DRY principle and avoid code duplication.
The answer to your first problem is to remove the sizeof(T) so you end up with this
for (int i = (size_ - 1); i > 0; i --) {
*(x_ + i + 1) = *(x_ + i);
}
The answer to your second problem is to change your declaration for your << overload to friend std::ostream & operator<<(std::ostream & x, Deque n) and initialize the body outside the class.
The answer to the third problem is that you can't return an int pointer which may point to a different block of memory location that what T could be.
The answer to the fourth question is to do the following:
Deque& operator=(const Deque& d) {
x_ = d.x_; // Deep copy
size_ = d.size_;
capacity_ = d.capacity_;
return *this;
}
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;
}
How do you copy an object of a class to another object of the same class just by using '='. I know that we have to overload the operator. here's what I have so far
#include<iostream>
#include<conio.h>
#include<iomanip>
using namespace std;
class arr
{
public:
int *arr1;
int len;
arr& operator = (const arr& eq) //for copying two arrays. <--- my overloader
{
arr temp1(eq.len);
arr *pttemp;
int i=0;
//temp.arr1=new int[eq.len];
//temp.len = eq.len;
for(i = 0 ; i < eq.len ; i++)
{
temp1.arr1[i] = eq.arr1[i];
}
pttemp = &temp1;
return temp1;
};
friend istream& operator >> (istream& ist, arr & r)
{
static int i = 0;
int *arrNew;
if (i == r.len)
{
r.len *=2;
arrNew = new int[r.len]; // allocate the new array
for(int j = 0; j < r.len/2; j++)// copy the old array to the first half of the new array
arrNew[j] = r.arr1[j];// delete the old array
delete [] r.arr1;// let arr point to the new array and continue use arr
r.arr1 = arrNew;
delete arrNew;
}
ist>>r.arr1[i];
i++;
return ist;
}
arr() //initializing constructor
{
len = 5;
arr1 = new int[len];
};
arr(int size) //initializing constructor with args
{
len = size;
arr1 = new int[len];
};
arr(arr& a) : arr1(a.arr1) //copy constructor
{
arr1 = new int[len];
};
~arr() //delete constructor
{
delete arr1;
};
};
void main()
{
int size = 5,i,temp,trig = 0;
arr orig(size), asc(size), desc(size);
//generate random numbers for orig
for (i = 0 ; i < size ; i++)
{
orig.arr1[i] = rand();
}
//copy original set to asc and desc
asc = orig;
desc = orig;
//sorting ascending
for (i = 0 ; i < size-1 ; i++)
{
trig = 1;
if (asc.arr1[i] < asc.arr1[i+1])
{
temp = asc.arr1[i];
asc.arr1[i] = asc.arr1[i+1];
asc.arr1[i+1] = temp;
trig = 0;
}
if (trig = 1)
break;
if (i == size - 1)
{
i = 0;
}
}
//sorting descending
for (i = 0 ; i < size-1 ; i++)
{
trig = 1;
if (desc.arr1[i] > desc.arr1[i+1])
{
temp = desc.arr1[i];
desc.arr1[i] = desc.arr1[i+1];
desc.arr1[i+1] = temp;
trig = 0;
}
if (trig = 1)
break;
if (i == size - 1)
{
i = 0;
}
}
//printing
cout<<"Original Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<orig.arr1[i]<<" ";
}
cout<<endl;
cout<<"Ascending Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<asc.arr1[i]<<" ";
}
cout<<endl;
cout<<"Descending Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<desc.arr1[i]<<" ";
}
cout<<endl;
getch();
}
It compiles properly but it ('asc' and 'desc') displays numbers that are different from the 'orig' object.
The proper solution is something like this:
struct Foo
{
std::vector<int> arr;
friend std::ifstream & operator>>(/*...*/);
};
The implicitly defined assignment operator already does exactly what you need, and clever code reuse is the heart of C++ programming ("a language for library design").
If you want to write it by hand, you have to make the copy yourself:
struct Bar
{
unsigned int len;
int * arr;
Bar & operator=(Bar const & rhs)
{
len = rhs.len;
delete[] arr;
arr = new int[len];
for (unsigned int i = 0; i != len; ++i) { arr[i] = rhs.arr[i]; }
return *this;
}
Bar() : len(), arr() { }
// more constructors
Bar(Bar const &); // exercise: write this!
~Bar() { delete[] arr; }
};
This is a terrible, terrible idea, though, since this pattern doesn't generalize at all: it isn't exception safe -- imagine one of the copies in the for-loop threw an exception. Now you've lost your original data and leaked memory.
A better solution would be to allocate a temporary buffer first:
int * temp = new int[len];
for (...) temp[i] = rhs.arr[i];
delete[] arr;
arr = temp;
Now this code is quickly getting very ugly, and imagine you had more than one of those!
In a nutshell: use std::vector.
You don't need a temporary array object in the assignment operator, and you should copy to the array in this, and then return *this:
arr &operator=(const arr &eq)
{
// If "this" already has an array, then delete it
if (arr1)
delete [] arr1;
// Create a new array of the same length as the one we're assigning from
len = eq.len;
arr1 = new int [len];
// And copy the array
memcpy(arr1, eq.arr1, len * sizeof(int));
// Returning "*this" allows the assignment operator to be chained
return *this;
}
what you have implemented in operator overloading is quite confusing and seems wrong to me
arr& operator = (const arr& eq) //for copying two arrays. <--- my overloader
{
arr temp1(eq.len);
arr *pttemp;
int i=0;
//temp.arr1=new int[eq.len];
//temp.len = eq.len;
for(i = 0 ; i < eq.len ; i++)
{
temp1.arr1[i] = eq.arr1[i];
}
pttemp = &temp1;
return temp1;
};
1.why are you creating a new object temp?
2.why create a pointer of type arr. and assigning pttemp to point to temp whose scope is with in the function and then you are not using
it anywhere!!
you need not create a new object inside the function as "this" pointer is implicitly passed to the function.
you should overload it this way
arr& operator = (const arr& source)
{
//this->len = source.len;
len = source.len;
for(int i=0;i < source.len ; i++)
{
//this->arr1[i] = source.arr1[i];
arr1[i] = source.arr1[i];
}
return *this;
}
Your copy constructor also looks wrong, it doesn't copy the contents of the array.
I agree with Kerrek that you should use vector. But since you appear to be trying to re-implement vector for yourself, here's a simple "correct" way to manage the resources in your class, for illustration:
class arr
{
public:
// switch order of data members, we want to initialize "len" first
int len;
int *arr1;
// default constructor
// you could use "new int[len]()" instead, to zero-initialize the array
arr() : len(5), arr1(new int[len]) {}
// constructor with size
arr(int size) : len(size), arr1(new int[len]) {}
// copy constructor
arr(const arr &rhs) : len(rhs.len), arr1(new int[len]) {
std::copy(rhs.arr1, rhs.arr1 + len, arr1);
}
// destructor
~arr() {
delete[] arr1; // *not* "delete", you *must* use "delete[]"
}
// swap function (this is useful, observe that it cannot throw)
void swap(arr &rhs) {
std::swap(len, rhs.len);
std::swap(arr1, rhs.arr1);
}
// assignment operator
arr &operator=(arr temp) { // parameter by value uses the copy ctor
// so, anything that could throw (the allocation) is complete,
// before we make any modifications to this object.
// see how useful "swap" is, and the fact it cannot throw?
swap(temp);
return *this;
}
// for C++11
// move constructor
arr(arr &&rhs) : len(rhs.len), arr1(rhs.arr1) {
rhs.arr1 = 0;
}
};
Btw, the name of the data member arr1 makes me fear that you're going to add a second array later. Do not do this, it's far more trouble to write a class that correctly manages two resources, than it is to write a class that correctly manages one resource and another class that has two of those as data members.