-
July 10th, 2009, 03:56 AM
#1
Copy constructor (invoking implicit one in user defined?)
I have a rather big class with many elementary data members (int, bool, etc.). The class contains one dynamically allocated member as well.
Due to this dynamic member, I have to define my copy constructor to properly perform deep copy.
However, there's also need to copy (assign) each and every elementary member in my copy constructor. This is tedious and error prone as I have to remember to update the copy contructor each time I add a data member to the class.
Is there any possibility how to solve the issue in more elegant way?
Is it somehow possible to invoke implicit (compiler defined) copy costructor to perform shallow copy and add just deep copy of the dynamic member?
Thanks for any advice.
-
July 10th, 2009, 04:03 AM
#2
Re: Copy constructor (invoking implicit one in user defined?)
Originally Posted by blueowl
Is there any possibility how to solve the issue in more elegant way?
Make it such that the dynamically allocated member manages its own memory, e.g., by using a smart pointer or container class instead, or otherwise creating a new class for that purpose. That way, you can treat the member as if it were like any built-in type: no need to worry about performing a deep copy.
-
July 10th, 2009, 04:37 AM
#3
Re: Copy constructor (invoking implicit one in user defined?)
Originally Posted by laserlight
Make it such that the dynamically allocated member manages its own memory, e.g., by using a smart pointer or container class instead, or otherwise creating a new class for that purpose. That way, you can treat the member as if it were like any built-in type: no need to worry about performing a deep copy.
I agree on the container, or the user defined class, but the smart pointer will most likely change the intended behaviour of the object since both the original and the copy will be pointing to the same resource with a compiler generated copy constructor and copy assignment operator. Admittedly on the odd occasion, that will be what the programmer wants, but it most likely will not be the case the majority of the time.
-
July 10th, 2009, 04:31 AM
#4
Re: Copy constructor (invoking implicit one in user defined?)
The normal way to not have to worry about how to assign vs how to copy construct is to write a swap function:
Code:
template <typename T>
class Buffer
{
public:
Buffer(size_t size)
:size_(size)
,buffer_( new T[size])
{}
Buffer(const Buffer& other)
:size_(other.size_)
,buffer_(new T[size_])
{
std::copy(other.buffer_, other.buffer_+size_, buffer_);
}
void swap(Buffer& other)
{
std::swap(size_, other.size_);
std::swap(buffer_, other.buffer_);
}
Buffer& operator=(const Buffer& rhs)
{
Buffer tmp(rhs);
swap(tmp);
return *this;
}
~Buffer()
{
delete [] buffer_;
}
private:
size_t size_;
T* buffer_;
};
Although I would recommend using the above pattern, I realise that it does not quite answer your question. The only way you can do it that I can think of, is create a base class that has a protected constructor and destructor and protected member variables. In the base class you everything you can copy copied by the compiler, and in your derived class you put the parts you want to manage.
Code:
struct Base
{
protected:
Base(int size)
:size_(size)
,capacity_(size)
{}
~Base(){}
size_t size_;
size_t capacity_;
};
template<typename T>
class Buffer : protected Base
{
public:
Buffer(size_t size)
:Base(size)
,buffer_( new T[size])
{}
Buffer(const Buffer& other)
:Base(other.size_)
,buffer_(new T[size_])
{
std::copy(other.buffer_, other.buffer_+size_, buffer_);
}
Buffer& operator=(const Buffer& rhs)
{
T* tmp = new T[rhs.size];
Base::operator=(rhs);
delete [] buffer_;
buffer_ = tmp;
std::copy(rhs.buffer_, rhs.buffer_+size_, buffer_);
return *this;
}
~Buffer()
{
delete [] buffer_;
}
size_t size() const { return size_; }
private:
T* buffer_;
};
You should see straight away that the above is not good design, it causes code bloat and is more error prone. A lot more logic needs to be applied to the assignment operator. I wouldn't advise you do it, the code is not as easy to follow for human beings, and a maintainer is therefore more prone to make a mistake.
The first solution is far cleaner with the swap function. Although it does require you to remember to add in a swap for each new variable you add, the design is far more robust, more readable and easier to maintain.
-
July 10th, 2009, 04:42 AM
#5
Re: Copy constructor (invoking implicit one in user defined?)
Originally Posted by PredicateNormative
but the smart pointer will most likely change the intended behaviour of the object since both the original and the copy will be pointing to the same resource with a compiler generated copy constructor and copy assignment operator. Admittedly on the odd occasion, that will be what the programmer wants, but it most likely will not be the case the majority of the time.
That is true, and is a good point since blueowl intends for copying, not referencing of the same object.
Originally Posted by PredicateNormative
The normal way to not have to worry about how to assign vs how to copy construct is to write a swap function:
That addresses how to perform an exception safe copy assignment, but it does not address blueowl's question on how to avoid the need "to update the copy contructor each time I add a data member to the class".
-
July 10th, 2009, 04:52 AM
#6
Re: Copy constructor (invoking implicit one in user defined?)
Originally Posted by laserlight
That addresses how to perform an exception safe copy assignment, but it does not address blueowl's question on how to avoid the need "to update the copy contructor each time I add a data member to the class".
True enough, but that was the reason for the second part of that post
I guess the point that I was trying to make is that it is possible to do by separating out the members into a protected base and a derived, but that at the end of the day it makes for code that is hard to follow, harder to maintain and more error prone.
Therefore I would just bite the bullet, and update the copy constructor, write a swap function, and make the assignment operator use the copy constructor and swap function. It's not what the OP wants but it does seem to be the better of the two options that I put forward.
Of course, they could do as you say, write a class to manage the resource, which to be honest is arguably an even better option.
-
July 10th, 2009, 05:20 AM
#7
Re: Copy constructor (invoking implicit one in user defined?)
Originally Posted by PredicateNormative
Therefore I would just bite the bullet, and update the copy constructor, write a swap function, and make the assignment operator use the copy constructor and swap function. It's not what the OP wants but it does seem to be the better of the two options that I put forward.
Of course, they could do as you say, write a class to manage the resource, which to be honest is arguably an even better option.
OK, thanks guys for your ideas.
The option to encapsulate the dynamic member (actually char *) to a class and manage it there is a nice solution. However I have doubts about performance. The object of my class is using quite extensively (calling thousand or even million times) and each calling of new constructors may worse performance.
swap() function is nice solution too, however it just solves copy constuctor/operator= duplicity.
My fisrt idea was some sort of invoking implicit copy constructor in my user-defined one.
Or perform "low level" member-wise copy of the class. But I don't know how to do it.
-
July 10th, 2009, 11:23 AM
#8
Re: Copy constructor (invoking implicit one in user defined?)
Originally Posted by PredicateNormative
True enough, but that was the reason for the second part of that post
I guess the point that I was trying to make is that it is possible to do by separating out the members into a protected base and a derived, but that at the end of the day it makes for code that is hard to follow, harder to maintain and more error prone.
Dunno, the second part of your post seems like a Rube Goldberg machine to me, and you appear to have admitted as much
Originally Posted by blueowl
The option to encapsulate the dynamic member (actually char *) to a class and manage it there is a nice solution. However I have doubts about performance. The object of my class is using quite extensively (calling thousand or even million times) and each calling of new constructors may worse performance.
If that is the case, then doing without such encapsulation would result in the same performance problem: either way, you would be copying some dynamically allocated arrays of char thousands or millions of times.
Note that you do not actually have to write a new class since you can use a std::vector<char> directly.
Originally Posted by blueowl
swap() function is nice solution too, however it just solves copy constuctor/operator= duplicity.
That is part of what it solves, but there is more: if your swap function is exception safe, your copy assignment operator would then be exception safe, and it is typically easy to make the swap function exception safe. Even if you use the compiler generated copy constructor and copy assignment operator, such a swap function can be useful because it could be more efficient, e.g., swapping pointers instead of doing unnecessary copying. (But I believe that there is no shortcut for a swap function other than to update it when the member variables are added or removed.)
-
July 13th, 2009, 04:16 AM
#9
Re: Copy constructor (invoking implicit one in user defined?)
Originally Posted by laserlight
Dunno, the second part of your post seems like a Rube Goldberg machine to me, and you appear to have admitted as much
Yep, I think that's a pretty accurate description.
Last edited by PredicateNormative; July 13th, 2009 at 04:20 AM.
Reason: spelling
-
July 13th, 2009, 05:02 AM
#10
Re: Copy constructor (invoking implicit one in user defined?)
You can embed the elementary members in an internal struct and copy the struct instance:
Code:
class MyLargeClass
{
struct
{
// data members go here
} members;
// dynamically allocated members go here
public:
MyLargeClass( const MyLargeClass& lhs ) :
members( lhs.members )
{
// make deep copy of dynamic objects
}
MyLargeClass& operator=( const MyLargeClass& lhs )
{
if( this != &lhs )
{
members = lhs.members;
// make deep copy of dynamic objects
}
return *this;
}
}
- Guido
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|