I haven't been able to find a good answer to this question.
I'm working on a C++ program and I'm trying to implement a function named copy which takes a reference to another object as an argument. Then, it returns a deep copy of this object.
Some background on my project: the Scene class contains a dynamic array (called "Images") of pointers to either NULL or an instance of the Image class, which is not shown here - but works as it should (it inherits all of its methods from a third party library, EasyBMP)
The reason I'm doing this is to avoid duplicating code in two places, but it's very possible that I'm taking the wrong approach.
I call this function in my assignment operator:
Scene const & Scene::operator=(Scene const & source)
{
if (this != &source) {
clear();
copy(source);
}
return *this;
}
And my copy constructor:
Scene::Scene(Scene const & source)
{
copy(source);
}
Finally, my copy() method looks like this:
Scene const & Scene::copy(Scene const & source)
{
Scene res(source.Max);
for (int i=0; i<res.Max; i++)
{
delete res.Images[i];
if (source.Images[i] != NULL)
res.Images[i] = new Image(*(source.Images[i]));
else
res.Images[i] = NULL;
}
return res;
}
Currently, it does NOT work. One problem I can see is that I'm trying to return a variable that goes out of scope as soon as the copy function ends. I tried returning a reference before, but the compiler threw errors and this wouldn't help with the scope issue anyways.
But I'm not even sure that my logic is right, i.e. can you even do something like this in a constructor? Or should I just explicitly write out the code in the copy constructor and assignment operator (without implementing the helper method copy)?
I'm very new to C++ and pointers, so any guidance would be much appreciated.
There's a way easier and more idiomatic way to do what you want: the copy-and-swap idiom.
// N.B. Not tested, but shows the basic structure of the copy-and-swap idiom.
class Scene
{
public:
Scene(int)
{
// Initialize a pointer array of Images
}
~Scene()
{
// Get rid of our pointer array of Images
}
// Copy constructor
// N.B. Not exception safe!
Scene(const Scene& rhs) : imgPtrArray(new Image*[rhs.max])
{
// Perform deep copy of rhs
for (int i=0; i < rhs.max; ++i)
{
if (rhs.imgPtrArray[i] != 0)
imgPtrArray[i] = new Image(*(rhs.imgPtrArray[i]));
else
imgPtrArray[i] = 0;
}
}
// Copy assignment constructor
// When this is called, a temporary copy of Scene called rhs will be made.
// The above copy constructor will then be called. We then swap the
// members so that this Scene will have the copy and the temporary
// will destroy what we had.
Scene& operator=(Scene rhs)
{
swap(rhs);
return *this;
}
void swap(Scene& rhs)
{
// You can also use std::swap() on imgPtrArray
// and max.
Images** temp = imgPtrArray;
imgPtrArray = rhs.imgPtrArray;
rhs.imgPtrArray = temp;
int maxTemp = max;
max = rhs.max;
rhs.max = maxTemp;
}
private:
Images** imgPtrArray;
int max;
};
That being said, I highly recommend that you pick up a good introductory C++ book, which will cover the basics of implementing the copy constructor and copy assignment operators correctly.
Scene const & Scene::operator=(Scene const & source);
overloaded assignment operator copies the content of this to the argument received source. For copy there is no need to return any thing or to create a local object. Just make a member wise copy from this to source.
void Scene::copy(Scene const & source){
// Member wise copy from this to source
}
Rule of three should be helpful to better understand more about these.
Related
I am quiet new to memory management in C++. I made a BigInt class that is now fully implemented except for the destructor which is impacting performance of the program. However, when I try to implement the destructor my program crashes.
In the following code for multiplying BigInts:
BigInt& BigInt::operator*=(BigInt const& other) {
//copy of this and other
BigInt* tempThis = new BigInt(*this); //1st number
BigInt* tempOther = new BigInt(other); //2nd number
//create temps so we can use value of BigInt before it is changed
BigInt* sum = new BigInt(0); //holds the eventual answer
BigInt* i = new BigInt(0);
//add *this BigInt to sum otherTemp amount of times
//this will yield multiplication answer.
for (*i; *i < *tempOther; *i = *i + 1) {
*sum += *this;
}
*this = *sum;
return *this;
}
The destructor is called when *i = *i + 1 is called in the for loop and then I think it gets deleted in my destructor which looks like this:
// destructor
BigInt::~BigInt() {
delete[] this->bigIntVector;
}
// copy constructor
BigInt::BigInt(BigInt const& orig)
: isPositive(orig.isPositive)
, base(orig.base)
{
this->bigIntVector = new BigIntVector(*(orig.bigIntVector));
}
Once 'i' is deleted nothing works and the whole program breaks.
If someone could give me a few pointers about destructors and how to fix my problem it would be great help. Thanks.
In C++, the same (horrible) arithmetic could be implemented as follows.
BigInt& BigInt::operator*=(BigInt const& other)
{
if(other==0)
return other;
if(other> 1)
for(BigInt old=*this,i=1; i!=other; ++i)
operator+=old;
else if(other<0) {
BigInt old=*this;
*this=0;
for(BigInt i=0; i!=other; --i)
operator-=old;
}
return*this;
}
assuming that the constructor from int, the copy constructor, the increment operator++ and the addition operator+= are all properly implemented (as well as the destructor).
Unfortunately, you failed to give us more information, but your copy constructor and destructor are definitely broken:
this->bigIntVector = new BigIntVector(*(orig.bigIntVector));
is followed by
delete[] this->bigIntVector;
giving you undefined behaviour (allocating with new but deallocating with delete[] -- delete[] is for memory allocated with new[]). I suspect you meant to copy the memory from the original in the copy constructor. However, you don't. If
class BigInt {
size_t size=0; // number of some_types allocated
some_type*bigIntVector=nullptr; // ptr to memory allocated, if any
/* rest of class */
};
then the copy constructor could be implemented like (assuming size is non-static)
BigInt::BigInt(BigInt const&orig)
: size(orig.size() // copy size
, bigIntVector(size? new some_type[size] : nullptr) // allocate memory
{ std::memcpy(orig.bigIntVector, bigIntVector); } // copy memory
However, (almost) the same could be implemented much easier with
class BigInt
{
std::vector<some_type> bigIntVector;
public:
BigInt(BigInt const&) = default;
BigInt(BigInt &&) = default;
BigInt&operator=(BigInt const&) = default;
BigInt&operator=(BigInt &&) = default;
/ * rest of class */
};
when the copy and move constructors (as well as the respective assignment operators) are automatically correctly created for you. You only need to address the default constructor, for example
BigInt::BigInt() // default constructor
: bigIntVector(1,some_type(0)) {} // size=1, value=0
and the constructors from built-in integer types. If you're new to C++, avoid new and delete in favour of standard library containers.
I thought the following example would have the same result as std::map::emplace(), but it didn't:
struct MoveTest {
MoveTest():
var(true)
{
cout << "ctor: " << static_cast<void*>(&var) << endl;
}
MoveTest(MoveTest&& mt):
var(std::move(mt.var))
{
cout << "move ctor: " << static_cast<void*>(&var) << endl;
}
bool var;
};
int main() {
map<int, MoveTest> mtest;
mtest.insert(make_pair(1, MoveTest()));
return 0;
}
output:
ctor: 0x7fff12e4e19b
move ctor: 0x7fff12e4e194
move ctor: 0x25f3034
The MoveTest::var has a different address in each move. It doesn't look like a "move". What's wrong in my code or understanding?
For MoveTest as you've defined it, there's not really much a move ctor (or assignment operator) can optimize (or do in general--all it can really do is copy from source go destination).
Moving is mostly a big win when an object contains a pointer to a bunch of external memory that's (for example) allocated on the heap. In this case, the move ctor/assignment operator can basically do a shallow copy (i.e., just grab the pointer from the moved-from object) instead of a deep copy (copying all the data referred to by that pointer).
For example:
class move_tst {
int *buffer;
static const int size = 1024 * 1024;
public:
move_tst() {
buffer = new int[size];
std::iota(buffer, buffer + size, 0);
}
move_tst(move_tst const &other) {
buffer = new int[size];
std::copy_n(other.buffer, size, buffer);
}
#ifdef MOVE
move_tst(move_tst &&other) {
buffer = other.buffer;
other.buffer = nullptr;
}
#endif
~move_tst() {
delete [] buffer;
}
};
Caveat: I've used a raw invocation of new and a raw pointer here so nothing else gets involved and we wouldn't (for example) get move semantics courtesy of a smart pointer. For normal code under normal circumstances, you should not be using either (raw pointer or raw invocation of new, I mean).
Edit: as far as what std::move does, it doesn't actually do a move itself--it just signals that you no longer care about a value, so it's eligible to be the source of a move, even if that destroys its value.
For example, with the class above, you could do a test like:
for (int i = 0; i < 1000; i++) {
move_tst src;
move_tst dst =src;
}
...and compare it to:
for (int i = 0; i < 1000; i++) {
move_tst src;
move_tst dst = std::move(src);
}
Without the std::move, dst will be created as a copy of src, but with the std::move, it'll be able to do a move from src to dst.
Your log simply tells that you create a temporary MoveTest instance with the default constructor
MoveTest()
which is then copied elsewhere, inside a pair object
make_pair(1, MoveTest())
and copied again somewhere inside the map object
mtest.insert(make_pair(1, MoveTest()));
There are three constructor invocations for three distinct MoveTest instances, each with its own address. As already well explained, whether the constructors are move constructors or old style copy constructors doesn't matter.
Did you expect some of the copies to be optimized away? With nontrivial code in the constructors it becomes unlikely; in particular, reading &var is a good reason to avoid shortcuts.
I am currently working on an ADT called Text and I'm overloading the assignment operator. When I test the operator like so: assignText = alpha everything outputs okay. However, when I do assignText = assignText then two solid bars output instead.
assignText is declared as a Text object.
My overloaded assignment operator is as follows:
void Text::operator= (const Text& other) {
bufferSize = other.getLength();
buffer = new char[bufferSize];
buffer = other.buffer;
}
Where int bufferSize and char *buffer
Any tips or suggestions would be greatly appreciated. If anything else is needed, just let me know.
Other answers already have pointed out various issues with your operator implementation. Here I'll try to understand what's happening for you, i.e. why the code behaves as you observe. If this == &other, i.e. during self assignment, you take the current length as the size of a new buffer. That new buffer isn't initialized, so at that point it might contain random bytes. The last assignment is a no-op in case of a self-assigment. To sum things up:
void Text::operator= (const Text& other) {
bufferSize = other.getLength(); // Take length from current object
buffer = new char[bufferSize]; // Create new buffer, old buffer turns into a memory leak
buffer = other.buffer; // No-op as both are the same variable
}
So what this tells you is that you end up with a buffer of the current object size but with undefined content. In your case that undefined content happens to represent the vertical bars you mention.
To solve this, make sure to fix the assignment operator based on the suggestions from other answers and comments.
This is a memory leak. You're assigning two different pointers to buffer.
buffer = new char[bufferSize];
buffer = other.buffer;
Regarding the problem at hand, that's covered by the C++ FAQ: "Why should I worry about "self assignment"?". It's often a good idea to read the FAQ first. Or at least skim it.
When you absolutely have to implement a copy assignment operator, usually the copy-and-swap idiom will be good enough. It's also exception safe. Goes like this:
void swapWith( MyType& other ) throw()
{
// swap them members
}
void operator=( MyType other )
{
swapWith( other );
}
Here the copy constructor creates the formal argument copy, and any exception happens there, so that the copy constructor centralizes also the cleanup in case of copy failure. After that the contents of the two objects are swapped, and the copy object's destructor takes care of cleaning up what was this object's internal stuff. The void result type is not yet conventional, but as I see it it's not smart to waste both code and time on supporting expressions with side effects, which are evil.
Now, you can avoid all this, simply by using std::vector for your buffer.
So that's what I recommend, the really simple solution: use std::vector.
This is because your assignment operator is fundamentally unsafe. You need to break the old state as the last step. Consider
Text& Text::operator= (const Text& other) {
auto new_buffer = new char[other.bufferSize];
std::copy(other.buffer, other.buffer + other.bufferSize, new_buffer);
// Now consider whether or not you need to deallocate the old buffer.
// Then set the new buffer.
buffer = new_buffer;
bufferSize = other.bufferSize;
return *this;
}
This ensures that if any problems are encountered, it is guaranteed that the Text object is always valid- and as a bonus, is self-assignment-safe. All well-written assignment operators are self-assignment safe.
This is often tied with copy-and-swap, which copies, then swaps- guaranteeing safety.
This piece of code will work perfectly
Text& Text::operator=(const Text& other)
{
if(this == &other) /* checks for self assignment */
return *this;
if(NULL == other.buffer)
return *this;
if(NULL != buffer) /* assuming buffer=NULL in constructor */
{
delete [] buffer;
buffer = NULL;
}
bufferSize = other.getLength();
buffer = new char[bufferSize+1];
memset(buffer, 0, bufferSize+1);
memcpy(buffer, other.buffer, bufferSize);
return *this;
}
Try this..
After some thought and review, I think I got it. Given that I need to write a void function dictated by the header file that I must construct my implementation from. I took into consideration the comments from Drew Dormann, MvG, as well as others and came up with this:
void Text::operator= (const Text &other)
{
if (this != &other) // takes care of self-assignment
{
delete [] buffer; // delete the old buffer
bufferSize = other.bufferSize; // assign size variable
buffer = new char[bufferSize + 1]; // create new buffer
strcpy(buffer, other.buffer); // copy array
}
}
This works and I believe it is memory leak free.
I am having erratic issue with my copy constructor.
I have a class MyData as follows:
class MyData
{
private:
std::vector<double> wavelength;
std::vector<double> amplitude;
public:
MyData::MyData(void) {}
MyData::MyData(const MyData &cSource)
: wavelength(cSource.wavelength), amplitude(cSource.amplitude)
{}
}
In my main program, I am inserting MyData objects into a ring buffer. This is how I am reading it back in main:
MyData data;
data = removeq(&q);
The problem is that sometimes the copied data is missing some values. Etc. if the original size of wavelength is 1, the copied data shows 0. I have debugged my program and the data in the ring buffer is correct etc it shows the correct size of 1.
Anyone have any idea if my copy constructor is wrong or do i need an assignment operator overload ??
Thanks!
The code i used for insert/remove into ring buffer:
void insertq(struct queue *p, MyData v)
{
int t;
t = (p->rear+1)%MAX;
if(t == p->front)
{ }
else
{
p->rear = t;
p->arr[p->rear] = v;
}
}
MyData removeq(struct queue *p)
{
MyData empty;
if(isempty(p))
{
return empty;
}
else
{
p->front = (p->front + 1)%MAX;
empty = p->arr[p->front];
return empty;
}
}
In order to call the copy constructor you have to declare and initialize your object (using another object) in the same line. Your current code actually calls the overloaded = operator.
A copy constructor is called when you create a new object from an existing object. Here, you are calling the assignment operator:
MyData data;
data = removeq(&q);
If you had used
Data oldDataObject;
Data newDataObject = oldDataObject;
the copy constructor will get invoked.
In the context of your code, you should override the '=' operator to solve this.
MyData& operator = (const MyData& data);
Thanks all for the advice. I have removed the copy constructor and assignment overload methods as suggested.
The issue was with the circular buffer structure I used. I changed the circular buffer code to this example here:
http://www.codeproject.com/Articles/43510/Lock-Free-Single-Producer-Single-Consumer-Circular
and it worked. There seem to be no more errors. I had initially thought that the problem was due to the copy or assignment operator as the error was intermittent and so I did not check if it was the circular buffer that was causing the error.
So having
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
{
// copy code in here ? using memcpy ? how???
}
ResultStructure& operator=(const ResultStructure& other)
{
if (this != &other) {
// copy code in here ?
}
return *this
}
int length;
char* ptr;
};
How to implement "copy constructor" and "assignment operator"? (sorry - I am C++ nube)
Update: sbi and others ask - why do I want to manually deal with raw memory? My answer is simple - In a students project I am part of now we use lots of C library's such as for example OpenCV OpenAL and FFmpeg and there are more to come. Currently using C++ we try to create a graph based direct show like cross platform library that would be helpful in live video broadcasting and processing. Our graph elements currently use char* and int pairs for data exchange. To cast data to subscribed elements we use raw memcpy now. I want to go further and make it possible for us to make our graph elements base C++ template. So that one graph element would be capable of of sharing current graph element data with other Graph elements and that data it shares would be a structure that would contain not one char* one int but any number of data fields and nearly any elements inside. So that is why I need to understand how to create a basic C++ structure that implements "copy constructor" and "assignment operator" for me to be capable to use new for us data casting algorithms like
void CastData(T item){
for(size_t i = 0 ; i < FuncVec.size(); i++){
T dataCopy = item;
FuncVec[i](dataCopy);
}
}
instead of currently used
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
delete[] dataCopy;
}
}
You might want to explain why you want to manually deal with raw memory. I haven't done this in a long time, it's what std::string and std::vector where designed for:
struct ResultStructure
{
// nothing else needed
std::string data; // or std::vector<char>
};
But if you really need to do this the hard way (is this homework?), then be advised that it is, at first, surprisingly hard to get this right. For example, a naive implementation of the assignment operator might be like this:
// DON'T TRY THIS AT HOME!!
ResultStructure& ResultStructure::operator=(const ResultStructure& rhs)
{
delete[] ptr; // free old ressource
ptr = new char[rhs.length]; // allocate new resourse
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr; // copy data
length = rhs.length;
}
If someone accidentally assigns an object to itself (which might happen if all you have is two references and you don't suspect them to refer to the same object), then this will fail fatally.
Also, what if new throws an exception? (It might throw std::bad_alloc if memory is exhausted.) Then we have already deleted the old data and have not allocated new data. The pointer, however, still points at where the old data used to be (actually, I think this is implementation-defined, but I have yet to see an implementation that changes a ptr upon deletion), and the class' destructor (you knew that class would need a destructor, right?) would then attempt to delete a piece of data at an address where no data is allocated. That's Undefined Behavior. The best you can hope for is that it crashes immediately.
The easiest way to do this is to employ the Copy-And-Swap idiom:
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
: ptr(new char[rhs.length]), length(rhs.length)
{
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr);
}
~ResultStructure() // your class needs this
{
delete[] ptr;
}
ResultStructure& operator=(ResultStructure rhs) // note: passed by copy
{
this->swap(rhs);
return *this
}
void swap(const ResultStruct& rhs)
{
using std::swap;
swap(length, rhs.length);
swap(ptr, rhs.ptr);
}
std::size_t length;
char* ptr;
};
Note that I have added a destructor, changed the assignment operator to pass the argument per copy (we need the copy constructor invoked to allocate memory), and added a swap member function. Per convention a swap() function never throws and is fast, preferably O(1).
I know that GMan's discussion of the Copy-And-Swap idiom is exhaustive enough to be and exhausting while mine is probably too terse for you, and you will likely not understand a lot of it at first, but try to persevere and to understand as much as possible.
If you use std::string, instead of char*, you would not even need to write operator= or copy-constructor. The compiler generated code would do your job very well.
But as a general solution (for some other scenario), use copy-and-swap idiom:
Copy-and-Swap Idiom
What is the copy-and-swap idiom?
Exceptional C++ by Herb Sutter has described these in great detail. I would recommend you to read items from this book. For the time being, you can read this article online:
Exception-Safe Generic Containers
The easy solution is to use a std::string instead of char* member.
Then the compiler-generated copy constructor and copy assignment operator just work.
As a rule, and especially as a novice, don't have raw pointer members.
Cheers & hth.,
As has been said, and as was recommending in the question this emanated from, you should probably reuse an existing container. At least the code would be right :)
For educational purposes though, let's examine this structure:
class Result
{
public:
private:
size_t length; // can't really be negative, right ?
char* data;
};
Here, we need explicit memory management. This implies, notably, following the Rule Of Three (say thanks to Fred)
Let's begin with actually building our object:
Result::Result(): length(0), data(0) {}
Result::Result(size_t l, char* d): length(0), data(0)
{
if (!d) { return; }
data = new char[l]; // this may throw, so we do it first
length = l;
memcpy(data, d, l);
}
Now we can implement the traditional operators:
// Swap
void Result::swap(Result& other)
{
using std::swap;
swap(length, other.length);
swap(data, other.data);
}
// Copy Constructor
Result::Result(Result const& other): length(0), data(0)
{
if (!other.length) { return; }
data = new char[other.length];
length = other.length;
mempcy(data, other.data, length);
}
// Assignemt Operator
Result& Result::operator=(Result other)
{
this->swap(other);
return *this;
}
// !IMPORTANT!
// Destructor
Result::~Result()
{
delete[] data; // use the array form of delete
// no need to test for nullity, it's handled
}
this is std::vector<char>'s job - or is this homework?
the vector would replace both length and the allocation behind ptr. the vector is the c++ idiom, and you'll not make friends with other c++ devs if you implement your classes like you've described. of course, there are corner cases, but standard containers such as vector are the default.
the vector knows how to copy chars as well as itself, and the implementations are optimized and tested.
here's how to explicitly implement copy ctor/assign using a vector:
struct ResultStructure {
ResultStructure(const ResultStructure& other) : d_chars(other.d_chars) {
}
ResultStructure& operator=(const ResultStructure& other) {
if (this != &other) {
this->d_chars = other.d_chars;
}
return *this;
}
std::vector<char> d_chars;
};
I think this should do the work:
struct ResultStructure
{
ResultStructure(const ResultStructure& other);
ResultStructure& operator=(const ResultStructure& other);
int length;
char* ptr;
};
ResultStructure::ResultStructure(const ResultStructure& other):length(other.length)
{
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
}
ResultStructure& ResultStructure::operator=(const ResultStructure& other)
{
length = other.length;
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
return *this;
}
Please remember about freeing ptr in destructor.
What is stored under ptr? If text, why not to use std::string? Anyway you can use std::vector. The constructors will be much easier then...
How is the memory to which ptr points allocated?
if using new, allocate with new, set length and then copy
other.length = length;
other.ptr = new char[length];
memcpy( other.ptr, ptr, length );
If you're allocating the memory with malloc, substitute a call to malloc in place of the call to new. If you're using some other memory scheme, figure it out. :)