Search code examples
c++segmentation-faultcopy-constructordeep-copyshallow-copy

Questions about a Segmentation Fault in C++ most likely caused by a custom copy constructor


I'm getting a segmentation fault which I believe is caused by the copy constructor. However, I can't find an example like this one anywhere online. I've read about shallow copy and deep copy but I'm not sure which category this copy would fall under. Anyone know?

MyObject::MyObject{
    lots of things including const and structs, but no pointers
}
MyObject::MyObject( const MyObject& oCopy){
    *this = oCopy;//is this deep or shallow?
}
const MyObject& MyObject::operator=(const MyObject& oRhs){
    if( this != oRhs ){
        members = oRhs.members;
        .....//there is a lot of members
    }
    return *this;
}
MyObject::~MyObject(){
    //there is nothing here
}

Code:

const MyObject * mpoOriginal;//this gets initialized in the constructor

int Main(){
    mpoOriginal = new MyObject();
    return DoSomething();
}

bool DoSomething(){
    MyObject *poCopied = new MyObject(*mpoOriginal);//the copy
    //lots of stuff going on
    delete poCopied;//this causes the crash - can't step into using GDB
    return true;
}

EDIT: Added operator= and constructor

SOLVED: Barking up the wrong tree, it ended up being a function calling delete twice on the same object


Solution

  • Wow....

    MyObject::MyObject( const MyObject& oCopy)
    {
        *this = oCopy;//is this deep or shallow?
    }
    

    It is neither. It is a call to the assignment operator.
    Since you have not finished the construction of the object this is probably ill-advised (though perfectly valid). It is more traditional to define the assignment operator in terms of the copy constructor though (see copy and swap idium).

    const MyObject& MyObject::operator=(const MyObject& oRhs)
    {
        if( this != oRhs ){
            members = oRhs.members;
            .....//there is a lot of members
        }
        return *this;
    }
    

    Basically fine, though normally the result of assignment is not cont.
    But if you do it this way you need to divide up your processing a bit to make it exception safe. It should look more like this:

    const MyObject& MyObject::operator=(const MyObject& oRhs)
    {
        if( this == oRhs )
        {
            return *this;
        }
        // Stage 1:
        // Copy all members of oRhs that can throw during copy into temporaries.
        // That way if they do throw you have not destroyed this obbject.
    
        // Stage 2:
        // Copy anything that can **not** throw from oRhs into this object
        // Use swap on the temporaries to copy them into the object in an exception sage mannor.
    
        // Stage 3:
        // Free any resources.
        return *this;
    }
    

    Of course there is a simpler way of doing this using copy and swap idum:

    MyObject& MyObject::operator=(MyObject oRhs)  // use pass by value to get copy
    {
        this.swap(oRhs);
        return *this;
    }
    
    void MyObject::swap(MyObject& oRhs)  throws()
    {
        // Call swap on each member.
        return *this;
    }
    

    If there is nothing to do in the destructor don't declare it (unless it needs to be virtual).

    MyObject::~MyObject(){
        //there is nothing here
    }
    

    Here you are declaring a pointer (not an object) so the constructor is not called (as pointers don;t have constructors).

    const MyObject * mpoOriginal;//this gets initialized in the constructor
    

    Here you are calling new to create the object.
    Are you sure you want to do this? A dynamically allocated object must be destroyed; ostensibly via delete, but more usually in C++ you wrap pointers inside a smart pointer to make sure the owner correctly and automatically destroys the object.

    int main()
    { //^^^^   Note main() has a lower case m
    
        mpoOriginal = new MyObject();
        return DoSomething();
    }
    

    But since you probably don't want a dynamic object. What you want is automatic object that is destroyed when it goes out of scope. Also you probably should not be using a global variable (pass it as a parameter otherwise your code is working using the side affects that are associated with global state).

    int main()
    {
         const MyObject  mpoOriginal;
         return DoSomething(mpoOriginal);
    }
    

    You do not need to call new to make a copy just create an object (passing the object you want to copy).

    bool DoSomething(MyObject const& data)
    {
        MyObject   poCopied (data);     //the copy
    
        //lots of stuff going on
        // No need to delete.
        // delete poCopied;//this causes the crash - can't step into using GDB
        // When it goes out of scope it is auto destroyed (as it is automatic).
    
        return true;
    }