CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10
  1. #1
    Join Date
    Jul 2009
    Posts
    5

    Question 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.

  2. #2
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Copy constructor (invoking implicit one in user defined?)

    Quote 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.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  3. #3
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    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.

  4. #4
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: Copy constructor (invoking implicit one in user defined?)

    Quote Originally Posted by laserlight View Post
    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.

  5. #5
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Copy constructor (invoking implicit one in user defined?)

    Quote 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.

    Quote 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".
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  6. #6
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: Copy constructor (invoking implicit one in user defined?)

    Quote Originally Posted by laserlight View Post
    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.

  7. #7
    Join Date
    Jul 2009
    Posts
    5

    Re: Copy constructor (invoking implicit one in user defined?)

    Quote Originally Posted by PredicateNormative View Post
    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.

  8. #8
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Copy constructor (invoking implicit one in user defined?)

    Quote 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

    Quote 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.

    Quote 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.)
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  9. #9
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: Copy constructor (invoking implicit one in user defined?)

    Quote Originally Posted by laserlight View Post
    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

  10. #10
    Join Date
    Nov 2006
    Location
    Essen, Germany
    Posts
    1,344

    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
  •  





Click Here to Expand Forum to Full Width

Featured