I am trying to overload operator + for my class as follows:
MyClass MyClass::operator +(const MyClass& rval) const {
MyClass ret(m_src); // m_src is member of MyClass: char* m_src;
ret.Add(rval); // this->m_src + rval, this method work correctly
return ret; // so, in ret.m_src I have correct value
} // but after this C++ call destructor for ret
Destructor:
delete[] m_src; // because in some methods I allocate dynamic memory
So, destructor clear memory and function return trash. How I can avoid this situation?
If I delete destructor, function work normal, but in this case I have memory leak :(
P.S: I can't change prototype of overloading +, unfortunately. Thanks.
You avoid this by replacing:
char *m_src;
by:
std::string m_src;
in your class MyClass.
With char * as a class member what you get is easy to go mess up manual memory management, you simply replace that with implicit RAII based memory management of std::string and save yourself all those troubles. And this is the very purpose of existence of std::string in C++.
If you cannot use standard library std::string class(though I simply fail to understand why), You need to make sure you are following the Rule of Three.
What you need is a copy constructor that copies m_src
MyClass::MyClass( const MyClass& ref ) {
m_src = new char[/*get len from ref*/];
memcpy( m_src, ref.m_src, /* len from ref */ * sizeof(char) );
}
Now you can change the operator+ to work with the copy constructor
MyClass MyClass::operator +(const MyClass& rval) const {
MyClass ret(rval); // use copy constructor
ret.Add(rval); // this->m_src + rval, this method work correctly
return ret; // so, in ret.m_src I have correct value
}
Related
Hello i got a class which looks like this:
class myClass{
public:
//other consturctors
//copy constructor:
myClass (const myClass & x)
: C1(x.C1), C2(x.C2), C3(x.C3), S1(x.S1) {};
//other functions
myClass & operator = (const myClass & x);
private:
const otherClass1 C1;
const otherClass2 C2;
const otherClass3 * C3;
string S1;
}
and I my problem is with assingment operator, because the compiler doesnt allow me to do it like in copy constructor. Thats problem because classes i need to assign doesnt have assign operator implemented and i cant edit them so I cant just do it like this:
myClass & operator = (const myClass & x) {
C1=x.C1; // -> compile error
C2=x.C2; // -> compile error
C3=x.C3;
S1=x.S1;
return *this;
}
So I've tried to implement the assign operator like:
myClass & operator = (const myClass & x) {
static myClass tmp(x);
return tmp;
}
althoght its working a little bit, I think its causing some problems in my program especially inserting to vector of myClasses doesnt work very well.
Could you guys give me advice how to correctly make assign operator to work like I need ? (remove old myClass and make myClass(copy) istead of old one, or somehow assign classes with this syntax :C1(copy.C1) ... {} ) ?
EDIT: Removing const from C1 and C2 seems to be solution to my problem.
you have const data members so you can't change them in assignment operator.
other noticeable thing is that you are doing shallow copy in your copy constructor, which you should avoid. you are only copying address in one pointer to another, it means both pointers will point to same address and if later on one deletes it, an other will become dangling pointer.
Forget about the 3rd piece of code with the static, you should try to get the second block of code working, and resolve the 2 compile errors.
If removing the constness does not work, you can store C1 and C2 on the heap.
const otherClass1 * C1;
const otherClass2 * C2;
Change them to pointers and new/delete them where needed, so you can use the copy constructor with a new, instead of the assignment operator (which you say does not exist for those classes)
I am trying to create a deep copy of a class by overloading the equals operator - however, it does not seem to be working. Any help appreciated!
This is the class I am trying to copy:
class CMap {
public:
int m_nWidth;
int m_nHeight;
char* m_pData;
void setDimensions(int nWidth, int nHeight);
void operator = (CMap* rhs);
};
this is my overloaded operator:
CMap& operator = (const CMap&rhs)
{
if (this == &rhs)
return *this;
memcpy(this -> m_pData, rhs.m_pData, sizeof(char)*rhs.m_nWidth*rhs.m_nHeight);
return *this;
}
and this is the function call in the main. myMap is an array of CMaps.
CMap tempMap;
tempMap.setDimensions(myMap[0].m_nHeight, myMap[0].m_nWidth);
tempMap.m_pData = myMap[0].m_pData;
First: that's not the equals operator, that's the assignment operator.
Second: The assignment operator should have a const & parameter, not a pointer, and returns a reference to the object, not anything.
Third: Except you do something which interferes with the semantics of copying, a assigment overload which does the copy is provided by the compiler automatically.
Respect the point three, you have done one thing which does not do "true" copying: Using a dynamic array through a pointer. The compiler will only copy the pointer, so you have to write your own operator= to copy the array by hand (What you are trying in the question).
The easiest solution is: Use a container like std::vector instead of manual memory management. It has implemented correctly copying and assigment, so yo do not have to write your own operator= in your class.
I want to redirect my copy operator to my copy constructor. Where in the latter I implement the proper logic for copying/contructing a new class based on the old avaialble class.
However, how is the proper way to do this? I "think" this one is maybe leaking memory, but I don't know how to do it without passing a pointer:
MyClass& MyClass::operator=(const MyClass& a) {
MyClass* b = new MyClass(a);
return *b;
}
Is this OK? If is not, what would be the proper way? Should I change the body of the method or the prototype?
Thank you.
No, an operator= should set the current object attributes to be the same as the object assigned. Your method assigns a new object on the heap, returns it as a reference (essentially leaking it) and leaves the object the operator was called on completely unchanged.
You should implement a method called, for example, CopyFrom(), which assigns all the object's attributes to match those of the passed in object (deep copying any heap allocated pointers whose lifetime is managed by MyClass) and then call THAT from both your copy constructor and your operator=.
class MyClass
{
public:
MyClass( const MyClass& in )
{
CopyFrom( in );
}
MyClass& operator=( const MyClass& in )
{
CopyFrom( in );
return *this;
}
private:
void CopyFrom( const MyClass& in )
{
... copies in's attributes into self.
}
};
As a rule, a copy assignment operator should never create a copy. Rather, it should copy data into the existing object that it's called on (the left-hand side of the assignment). For example:
class MyClass
{
public:
MyClass & operator = (const MyClass & RHS)
{
// Copy data from RHS into 'this'
m_value = RHS.m_value;
return *this;
}
private:
int m_value;
};
In this case, defining your own copy constructor isn't necessary because the default (compiler-provided) one would work fine. It's just an illustration though.
Unfortunately you can't invoke the copy constructor on the existing object. The copy-swap pattern is an alternative, but it can be less efficient.
Unless you're storing pointers inside of MyClass, the correct copy assignment operator is the default-generated one. If, however you need to implement one, you can write it in terms of your copy-constructor via the copy-swap idiom:
MyClass& MyClass::operator = (MyClass const& a) {
MyClass temp(a); // Call the copy constructor
using std::swap;
swap(temp, *this);
return *this;
}
The reason for the using std::swap is to enable argument-dependent lookup. If you define your own swap function for MyClass, it will be called. Else std::swap will be used as a fallback. (EDIT: You do in fact need to implement a custom swap in this case, or else you will get infinite recursion. std::swap will use the assignment operator, which will call std::swap, which will call the...)
The reason that this idiom is well-liked is because std::swap is a no-throw function. If your copy-constructor were to throw an exception, then your object you're assigning to is still in a valid state.
The "proper way" is to implement the assignment operator like an assignment operator: modify the contents of the object on which the operator is being called and return a reference to it.
Your current implementation will result in a memory leak, AND doesn't do any assignment (which is the main point of the assignment operator).
If you only want to write the assignment code once, and your class doesn't allocate memory in the constructor, you could do this:
MyClass::MyClass(const MyClass& a) {
*this = a;
}
MyClass& MyClass::operator=(const MyClass& a) {
if (&a == this)
return *this;
// Do assignment
return *this;
}
But I wouldn't recommend it.
Your code is totally wrong (sorry)! The assignment operator does
not assign anything, but allocates a pointer to a MyClass object,
creating a memory leak. My advice: avoid pointers or use some
smart pointer (shared_ptr, unique_ptr), but that is just a side note.
Maybe this is helpful:
#include <iostream>
#include <limits>
class X
{
public:
X(std::size_t n)
: m_size(n), m_data(new int[n])
{
std::cout << "Construct" << std::endl;
}
~X()
{
std::cout << "Destruct" << std::endl;
delete [] m_data;
}
// Exception safe assignment.
// Note: I am passing by value to enable copy elision and
// move semantics.
X& operator = (X x) {
std::cout << "Assign" << std::endl;
x.swap(*this);
return *this;
}
void swap(X& x) {
std::swap(m_size, x.m_size);
std::swap(m_data, x.m_data);
}
std::size_t size() const { return m_size; }
private:
std::size_t m_size;
int* m_data;
};
int main()
{
X x(1);
try {
x = X(2);
// To provoke an exception:
std::size_t n = std::numeric_limits<std::size_t>::max();
x = X(n);
}
catch(...) {
std::cout << "Exception" << std::endl;
}
std::cout << "Size: " << x.size() << std::endl;
return 0;
}
If you absolutely want to implement the assignment operator by copy constructor, use the following:
MyClass& MyClass::operator=(const MyClass& o)
{
this->~MyClass(); // destroy current object
new(this) MyClass(o); // use the copy constructor
return *this;
}
I cannot think of any situation in which this would be the best thing to do (other answers describe ways of implementation that are better in some situations).
Maybe (just trying to make things up here) if MyClass contains hundreds of int/float fields, and several dynamically-allocated pointers?
Duplicating them in constructor and assignment operator is too tedious and error-prone
Having a copying function that both constructor and assignment operator call - not ideal, because pointers have to be set to NULL first
The code above - will work with no additional effort!
However, having bare (non-smart) pointers in your class is discouraged. If you have such a class, then you have far worse problems than non-working assignment operator - you have to refactor first, and the problem will go away, together with all other bugs.
Our professor posted a custom 'String' template file online, and asked us a while ago to fill out the functions below. My question, in order to try and understand this, is why the top three constructors have Text = NULL; and below it, this = source;, some other form of it. I feel like each should say Text = the_input_parameter.
Many thanks, here's the code:
class String
{
public:
// Default constructor
String()
{
Text = NULL;
}
String(const String& source)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = source;
}
String(const char* text)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = text;
}
~String()
{
delete[] Text;
}
// Assignment operator to perform deep copy
String& operator = (const char* text)
{
// Ddispose of old Text
delete[] Text;
// +1 accounts for NULL-terminator
int trueLength = GetLength(text) + 1;
// Dynamically allocate characters on heap
Text = new char[trueLength];
// Copy all characters from source to Text; +1 accounts for NULL-terminator
for ( int i = 0; i < trueLength; i++ )
Text[i] = text[i];
return *this;
}
// Returns a reference to a single character from this String
char& operator [] (int index) const
{
int length = GetLength();
// Check for valid index
if ( (index < 0) || (index > length) )
{
stringstream error;
error << "operator[] - index " << index << " is out of bounds (0.." << (length - 1) << ")";
throw String(error.str().c_str());
}
return Text[index];
}
private:
// The encapsulated C-string
char* Text;
};
Why you should not implement constructors in terms of assignment:
It gets pretty nasty in derived classes. Think about it.
It's difficult to make exception safe.
It's also inefficient, to boot (requiring default construction then assignment).
So the answer to why it’s done that way in your example code, is possibly that your professor doesn’t know diddly about C++ programming.
Otherwise, it's difficult to say: it just doesn't make any sense at all to do that.
Going the other way, however, namely implementing copy assignment in terms of copy construction, is very common and is known as the copy-and-swap idiom.
It's simple, exceptions safe and generally efficient, and goes like this:
class Foo
{
public:
void swap_with( Foo& other ) throw()
{
// No-throwing swap here.
}
void operator=( Foo other )
{
other.swap_with( *this );
}
};
yup, that's all.
variants include naming the swapper just swap, and letting the assignment operator return a reference, and some prefer to pass the argument by reference and then make a copy (using copy construction).
It's just a way to factor out common code into a helper function. In this case, operator=() acts as the helper function. Its function is to deallocate the current string (in this case, NULL) and perform a deep copy of the right-hand side.
I feel like each should say Text = the_input_parameter.
For String(const String& source) this wouldn't compile since source isn't the right type.
For String(const char* text) this wouldn't be correct since that would just assign the pointer instead of performing a deep copy.
The above assumes you are only showing us a part of the class, and that the actual class defines an appropriate assignment operator and a destructor. If it doesn't, you need a new professor.
The class manages memory, so destructor releases it, and assignment operator allocates new for new data and releases old one (shoud be in that order).
Then the explanation of initial assignment is clear: you need to initialize the member field to a correct value, as otherwise it will contain garbage (some pointer to somewhere), which code will attempt to use and free.
Though it is not seen from the code, there might be also assignment for const String& and type cast operator operator const char *() const.
I'm working on my assignment in C++ course.
I have to create operator+= which will add an object to another set of object.
So, how do I implement operator+= here?
class classNew
{
anotherClass *my_objects;
public:
// TODO: classNew(int, char const *)
classNew operator+=(const anotherClass & rhs);
};
int main()
{
classNew d1(7, "w");
anotherClass sgs[5];
// somehow init sgs[0]..[4]?
for (int i=0; i<sizeof(sgs)/sizeof(*sgs); ++i)
d1 += sgs[i];
}
UPDATE:
I have something like this
newClass newClass::operator+=(const anotherClass& seg){
this->my_objs[n_seg] = seg;
return *this;
}
Unless your operator+= is intended to modify the object you're adding, which would be highly unusual, I'd suggest one two simple changes to the signature:
classNew & classNew::operator+=(const anotherClass& rhs);
You always want to return a reference to the class, otherwise you get a copy.
You have a pointer to anotherClass in your class, I assume that this is actually a pointer to an array. You simply have to copy the passed rhs to the appropriate spot in your array, reallocating it and growing it if necessary. If my assumption is incorrect, you just need to do whatever addition is defined as for your class.
If this weren't an assignment I would also suggest replacing the pointer with a std::vector<anotherClass>.