views:

1613

answers:

4

Please write a list of tasks that a copy constructor and assignment operator need to do in C++ to keep exception safety, avoid memory leaks etc.

A: 

I have no idea about exception safely here but I go this way. Let's imagine it's a templated array wrapper. Hope it helps :)

Array(const Array& rhs)
    {
        mData = NULL;
        mSize = rhs.size();
        *this = rhs;
    }

    Array& operator=(const Array& rhs)
    {
        if(this == &rhs)
        {
            return *this;
        }

        int len = rhs.size();

        delete[] mData;

        mData = new T[len];

        for(int i = 0; i < len; ++i)
        {
            mData[i] = rhs[i];
        }

        mSize = len;

        return *this;
    }
Nazgob
This code is not exception safe.Always allocate before releasing!
Luc Hermitte
No it's not. I had no issues with exceptions safe code so I never had a chance to practice it. This one above is ofc just snipper, normally you use STL containers. Please post your snippet, I'd like to take a look at it.
Nazgob
There are plenty of snippets in the links I've provided in my response.BTW, the test preventing the self-assignment is considered as an anti-idiom now (now that exceptions are better understood)
Luc Hermitte
Hmmm, I'm definitely gonna check it out. Thanks!
Nazgob
"BTW, the test preventing the self-assignment is considered as an anti-idiom now" Link to explanation for this?
abababa22
I've given the link*s* in my other message -> see GOTW and the FAQ C++ lite.
Luc Hermitte
The summary is that copy-and-swap deals with self-assignment automatically, but not efficiently. An extra check slows down other-assignment. So the performance trade-off is unknown, as it depends on what proportion of assignments are self-, and the code is simpler without the check.
Steve Jessop
The self-assignement test does not ensure exception safety, while an exception safe code is robust regarding the self-assignement issue.The copy-and-swap is just one of the multiple ways to be exception safe.
Luc Hermitte
+11  A: 

First be sure you really need to support copy. Most of the time it is not the case, and thus disabling both is the way to go.

Sometimes, you'll still need to provide duplication on a class from a polymorphic hierarchy, in that case: disable the assignment operator, write a (protected?) copy constructor, and provide a virtual clone() function.

Otherwise, in the case you are writing a value class, you're back into the land of the Orthogonal Canonical Form of Coplien. If you have a member that can't be trivially copied, you'll need to provide a copy-constructor, a destructor, an assignment-operator and a default constructor. This rule can be refined, see for instance: The Law of The Big Two

I'd also recommend to have a look at C++ FAQ lite regarding assignment operators, and at the copy-and-swap idiom and at GOTW.

Luc Hermitte
I thought it was called the rule of 4.
Martin York
AFAIK, it originates from Jim Coplien's book, hence the name -- BTW it only applies to value classes. Some call it the rule of four. There is (was?) also explanations about /Rule of Big Three/ in C++ FAQ lite (I can't find it anymore). And it can be reduced to two thanks to RAII.
Luc Hermitte
Also protect against self-assignment in the assignment operator.
Adrian McCarthy
+3  A: 

The compiler generated versions work in most situations.

You need to think a bit harder about the problem when your object contains a RAW pointer (an argument for not having RAW pointers). So you have a RAW pointer, the second question is do you own the pointer (is it being deleted by you)? If so then you will need to apply the rule of 4.

Owning more than 1 RAW pointer becomes increasingly hard to do correctly (The increase in complexity is not linear either [but that is observational and I have no real stats to back that statement up]). So if you have more than 1 RAW pointer think about wrapping each in its own class (some form of smart pointer).

Rule of 4: If an object is the owner of a RAW pointer then you need to define the following 4 members to make sure you handle the memory management correctly:

  • Constructor
  • Copy Constructor
  • Assignment Operator
  • Destructor

How you define these will depend on the situations. But things to watch out for:

  • Default Construction: Set pointer to NULL
  • Copy Constructor: Use the Copy and Swap ideum to provide to the "Strong Exception Guarantee"
  • Assignment operator: Check for assignment to self
  • Destructor: Guard against exceptions propagating out of the destructor.
Martin York
"The compiler generated versions work form most situations." - depending what kind of programming you do. Even if everything is smart pointers, dealing with resource tracking and exception issues, a shallow copy may not be what you want semantically.
Steve Jessop
+1  A: 

try to read this.

http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html

is a very good analysis of Assignment operator

ugasoft
This is typically what I'd ask in an interview. However, I see a false assumption: that most objets require to be copiable. "Every object in a well-designed C++ system has a default constructor, a copy constructor, and an assignment operator." This sentence is for value based objects, not entities.
Luc Hermitte