purepureluck
purepureluck

Reputation: 1311

What happens when I modify the copy constructor to do something weird and then pass an object (of that class) by value to a function?

class C
{
public:
  C(C& c)
  {
    i = c.i;
    j = 100;
  }
  C() : i(0), j(0)
  {
  }

  int i, j;
};

C func(C c)
{
  return c;
}

int main()
{
  C c;
  c = func(c)
  // What is the value of j?
}

Above is a class with an unusual copy constructor. Instead of copying i and j, it copies i and assigns something else to j. What happens when I pass an object of the class to the function?

Edit: It just seems like such a tricky thing to do in a program...

Upvotes: 1

Views: 281

Answers (4)

Kerrek SB
Kerrek SB

Reputation: 477378

It is your responsibility to equip your class with a copy constructor such that the expression Foo x(y); results in an object x that is semantically equal to y. Nobody forces you to do that in any particular way, and the program will behave as you tell it to.

Consider this simplified example:

struct Foo
{
    int value;
    explicit Foo(int n) : value(n) { }
    Foo(Foo const & rhs) : value(rhs.n / 5 - 32) { } // tee-hee
};

Foo make_it_so() { return Foo(40); }

int main() { Foo k = make_it_so(); }

Now depending on whether the copy constructor is elided or not, k.value ends up either with 40 or with -24. However, because you wrote the copy constructor, you have essentially declared that you consider the two semantically equal.

C++ lets you set the rules of the game, but it doesn't protect you from going straight to jail.

(I know that my example is slightly different from what you asked in your question ("argument passing"), but it is intended to illustrate your responsibilities as an author.)

Upvotes: 1

pmr
pmr

Reputation: 59831

The obvious happens. The object is copied. The values are set to whatever you do in the copy constructor. You can confirm this by simply printing the values.

Copy-elision is not allowed here as the argument passed into the function is not an rvalue. If it were an rvalue (e.g. func(C())) the code would not compile as the temporary cannot be bound to the copy constructor as it is taking a reference as argument and not a reference to const. If this is fixed, copy-elision can be observed for the argument and the return value. So the state of c after being assigned to could be the one of a default constructed C.

As far as I understand the code as shown will always show the same behavior and does not depend on optimizations.

Upvotes: 0

Kerr
Kerr

Reputation: 431

When you write a copy constructor with the same signature as the default copy constructor, you are suppressing the default one from being created.

So when the code calls for the default copy constructor it will run the one you have made and do whatever you put in there, be it printing, memory allocation, or even just do nothing if that is how you coded it.

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283733

The copy constructor may be called, in which case your weird behavior happens.

Or, the compiler may elide the copy (this is specifically allowed by the standard), breaking your expectations. In this particular case that isn't allowed, but in many contexts it is.

So don't write copy-constructors that do weird things. (Or else we will call you auto_ptr)

Upvotes: 8

Related Questions