Thread: Copy constructors and the = operator

  1. #1
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902

    Copy constructors and the = operator

    A lot of the tutorial sites that I've seen have copy constructors and = operators that contain much the same code. My question, therefore, is the following valid?
    Code:
    SomeClass::SomeClass(const SomeClass &sc)
    {
       *this = sc; // After all, we're copying sc, and what is copying but an assignment?
    }
    
    SomeClass::operator = (const SomeClass &sc)
    {
       if(this == &sc) return *this;
    
       // Do copy, freeing current data items as needed.
       return *this;
    }
    This seems to be the easiest way to do a copy constructor, as are these two examples below not functionally equivalent:
    Code:
    // SomeClass scA has been previously defined / initialzed with data.
    SomeClass scB(scA);
    SomeClass scC = scA;
    SomeClass scD;
    scD = scA;
    // Are not all those functionally equivalent?
    // (Only differing between when the data is set to a value?)
    Just wondering if what I'm writing is legal. I've used the above (calling operator = in the copy constructor) and never ran into any problems... just want to know if it's waiting to blow up in my face or not.
    Thanks.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I am not entirely sure if such assignment to *this is valid, but from what I know you should do it the other way: implement the copy assignment operator in terms of the copy constructor, using a swap() member function.
    Code:
    SomeClass::SomeClass(const SomeClass &sc)
    {
        // perform copy
    }
    
    SomeClass& SomeClass::operator = (const SomeClass &sc)
    {
        if (this != &sc)
        {
            SomeClass temp(sc);
            swap(temp);
        }
        return *this;
    }
    The check for this != &sc may be unnecessary if swap() can handle swapping an object with itself, but then you might want to avoid copy construction if it is expensive.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Laserlight's way is best. Operator= usually duplicates the code for the copy constructor and destructor; using the method laserlight did, that's taken care of.

    There's an even better reason to do it like this -- IF you make sure that swap() cannot throw an exception, then your code is exception-safe and has commit-or-rollback semantics; in the event of an exception in constructing temp, the object remains unchanged.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  4. #4
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Using the assignment operator from within the copy-constructor causes problems when the assignment operator usually takes care of decllocating existing resources before assigning new ones. But if the internal members are not initialised yet, it might try destroying garbage.
    Such assignment operator behaviour is usually the case in implementations of smart pointer.
    Last edited by iMalc; 03-27-2007 at 02:58 AM.

  5. #5
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Code:
    SomeClass scC = scA;
    FYI, such assignments are transformed by the compiler into:
    Code:
    SomeClass scC(scA);
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  6. #6
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218
    Does that mean it's faster to do scC(scA) than scC = scA?

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Does that mean it's faster to do scC(scA) than scC = scA?
    Probably, and copy construction should be no slower than copy assignment since for you to be able to assign, the object to assign to must have already been constructed.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Quote Originally Posted by iMalc View Post
    Using the assignment operator from within the copy-constructor causes problems when the assignment operator usually takes care of decllocating existing resources before assigning new ones.
    That's actually a bad way to do things. Better is to create new, temporary resources, then when the resources have been allocated correctly, swap the temp and the object and let the destructor deallocate.

    Else, if you deallocate an existing resource but have a thrown exception when trying to allocate the new one, your object is left with neither the old resource nor the new.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  9. #9
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318

    Smile Absolutely

    Quote Originally Posted by Cat View Post
    That's actually a bad way to do things. Better is to create new, temporary resources, then when the resources have been allocated correctly, swap the temp and the object and let the destructor deallocate.

    Else, if you deallocate an existing resource but have a thrown exception when trying to allocate the new one, your object is left with neither the old resource nor the new.
    Oh I know, I agree totally! I shouldn't have put the word "before" in there as it clouded the issue. Regardles of the order of allocation and deallocation of new and existing recourses, the existing resources are invalid/uninitialised, and calling the assignment operator in that case will fail.
    My point is that any assignment operator that assumes the object is already constructed will fall over, if the object is not in fact already constructed, such as when you use it from the copy-constructor.

Popular pages Recent additions subscribe to a feed