Creating an easy to maintain copy constructor

后端 未结 9 2511
夕颜
夕颜 2021-02-19 13:55

Consider the following class:

class A {

char *p;
int a, b, c, d;

public:
   A(const &A);
};

Note that I have to define a copy constructor

相关标签:
9条回答
  • 2021-02-19 14:09

    The question is, do you really need a pointer with deep-copy semantics in your class? In my experience, the answer almost always is no. Maybe you could explain your scenario, so we may show you alternative solutions.

    That said, this article describes an implementation of a smart-pointer with deep-copy semantics.

    0 讨论(0)
  • 2021-02-19 14:18

    As a rule of thumb: If you have to manually manage resources, wrap each into its own object.

    Put that char* into its own object with a proper copy constructor and let the compiler do the copy constructor for A. Note that this also deals with assignment and destruction, which you haven't mentioned in your question, but need to be dealt with nevertheless.
    The standard library has several types to pick from for that, among them std::string and std::vector<char>.

    0 讨论(0)
  • 2021-02-19 14:19

    So the default copy constructor is called first and then the deep copy is performed. Unfortunately this doesn't seem to work.

    Is there any better way to do this? One restriction - I can't use shared/smart pointers.

    If I understand correctly, your question, you could consider using an initialization function:

    class A
    {
        int i, j;
        char* p;
    
        void Copy(int ii, int jj, char* pp); // assign the values to memebers of A
    public:
        A(int i, int j, char* p);
        A(const A& a);
    };
    
    A::A(int i, int j, char* p)
    {
        Copy(i, j, p);
    }
    
    A::A(const A& a)
    {
        Copy(a.i, a.j, a.p);
    }
    

    That said, you really should consider using RAII ( there's a reason people keep recommending it :) ) for your extra resources.

    If I can't use RAII, I still prefer creating the copy constructor and using initializer lists, for every member (actually, I prefer doing so even when using RAII):

    A::A(int ii, int lj, char* pp)
        : i(ii)
        , j(jj)
        , p( function_that_creates_deep_copy(pp) )
    {
    }
    
    A::A(const A& a)
        : i(a.i)
        , j(a.j)
        , p( function_that_creates_deep_copy(a.p) )
    {
    }
    

    This has the advantage of "explicitness" and is easy to debug (you can step in and see what it does for each initialization).

    0 讨论(0)
  • 2021-02-19 14:23

    You could separate your copyable members into a POD-struct and mantain your members requiring a managed copy separately.

    As your data members are private this can be invisible to clients of your class.

    E.g.

    class A {
    
    char *p;
    
    struct POData {
        int a, b, c, d;
        // other copyable members
    } data;
    
    public:
       A(const &A);
    };
    
    A(const A& a)
        : data( a.data )
    {
        p = DuplicateString( a.p );
        // other managed copies...
        // careful exception safe implementation, etc.
    }
    
    0 讨论(0)
  • 2021-02-19 14:23

    While I agree with others saying that you should wrap the pointer in its own class for RAII and let the compiler synthesise the copy contructor, destructor and assignment operator there is a way around your problem: declare (and define) private static function which will do whatever is needed and common for different constructors and call it from there.

    0 讨论(0)
  • 2021-02-19 14:30

    Always use RAII objects to manage unmanages resources such as raw pointers, and use exactly one RAII object for each resource. Avoid raw pointers in general. In this case, using std::string is the best solution.

    If that's not possible for some reason, factor the easy to copy parts out into a base class or a member object.

    0 讨论(0)
提交回复
热议问题