1

Consider this piece of code:

class complex{
        private:
                double re, im;
        public:
                complex(double _re, double _im):re(_re),im(_im){}
                complex(complex c):re(c.re),im(c.im){}
};

I already knew that the copy constructor complex(complex c) will cause infinite recursion.

However, it should only pick const reference copy constructor complex(const complex &c) as the function for copying, since this is the default behavior if it is not explicitly specified. Every thing else is excluded, such as complex(complex c).

Why does it apply the function with pass by value here? Or both are copy constructors, except the pass by value cannot be modified and is used to pass to other functions rather than its constructor?

I think in Java, it is permitted to do like that, since it will just copy the object into the constructor.

Amumu
  • 17,924
  • 31
  • 84
  • 131
  • You might want to add the example I gave from your last question: `complex(complex c)` and `complex(const complex &c)` – Mysticial Dec 08 '11 at 20:00
  • "Why does it apply the function with pass by value here?" Is there something missing in this question? – pmr Dec 08 '11 at 20:04
  • @pmr refer to my previous question which was closed not so long ago, since there were so many duplicates: http://stackoverflow.com/questions/8436467/why-is-copy-constructor-not-allowed-pass-by-value – Amumu Dec 08 '11 at 20:05
  • @pmr I think the OP is asking whether or not it's valid to overload: `complex(complex c)` and `complex(const complex &c)` And if it's valid, what will happen. – Mysticial Dec 08 '11 at 20:08

3 Answers3

3

A copy constructor must be in on of the following forms:

T(T&);
T(const T&);

That is, a constructor is a copy constructor only if it takes a single parameter of reference class type. A constructor that takes a single parameter of class type by-value is, by definition, not a copy constructor (edit) -- and in fact is illegal, as pointed out by Cat Plus Plus.

12.1 : Constructors

10/A copy constructor for a class X is a constructor with a first parameter of type X& or of type const X&

Beyond this Standardese, however, is a fundamental error in your understanding of the copy constructor. Consider the following code:

class Foo
{
public:
  Foo() {}
  Foo(Foo f) {/*...*/};
};

int main()
{
  Foo f1;
  Foo f2(f1);
}

When f2 is constructed f1 is passed by-value. In order to evaluate the parameters for the constructor call, f1 must be copied. So, you see there is a paradox here. In order to call the copy constructor, you must make a copy. In order to make a copy, you must call the copy constructor...

The above must call the constructor with an argument by-value simply because that is what the type of the parameter is: it's a Foo by-value. It it were not by-value, it would have to be either by reference, which looks like this:

Foo(Foo& rhs)
/* or like this: */ Foo(const Foo& rhs);

...or it must take it by pointer, which looks like this:

Foo(Foo* prhs)

...but, in the latter case, this is obviously not a copy constructor given the definition above.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • He already knew about the infinite recursion that passing by value causes. – Seth Carnegie Dec 08 '11 at 20:08
  • Ah, so it's the ambiguity between the two function calls, since either passing by ref or by value, the caller uses the same function call. The compiler would mistake and call the copy by value constructor. Is my understanding correct? – Amumu Dec 08 '11 at 20:14
  • @Amumu no, the compiler would not compile code with a "copy constructor" that took its argument by value (or it shouldn't at least, whether it does or not is a different issue). – Seth Carnegie Dec 08 '11 at 20:15
  • @Seth yes, the compiler would mistake the call to the wrong function, then it produces error. I think the early day it would allow this notation to compile, and as you said, even VS permit. The point of the question is that I want to know why. – Amumu Dec 08 '11 at 20:17
  • @Amumu: There *is no such thing* as a "copy by value" constructor. – John Dibling Dec 08 '11 at 20:17
  • @Amumu if the compiler does not reject the copy-by-value-copy-constructor, then the compiler isn't conforming to the C++ standard and you'll have to ask the people who wrote the compiler why they didn't conform to the standard. – Seth Carnegie Dec 08 '11 at 20:18
  • @John Ok I know there's no such thing, and error is produced as I posted in my previous question (look up the comment in my first post). What I fail to understand at first is that why it doesn't allow such action to be performed, and as suggested by Stroustrup, allow such action will lead to infinite recursion. Obviously this must happen before. – Amumu Dec 08 '11 at 20:20
  • @Amumu: I don't understand your question, or the premise of your question. **What** has happened before? – John Dibling Dec 08 '11 at 20:22
  • @John The error for allow such action to perform. If not, how can he know there's infinite recursion, if he did not test. He must have experience with it, so he can safely wrote that statement into his book. – Amumu Dec 08 '11 at 20:24
  • @Amumu: Stroustup invented C++ -- it's his baby. He ought to know. But, think about it. Imagine you were designing a new language from scratch, and your classes had constructors that took arguments of that type by-value. Since it is by-value, it must make a copy before calling the constructor, right? So, if you were the language designer, how would you implement this? – John Dibling Dec 08 '11 at 20:27
  • @John Of course it should use copy by reference. The problem here I think, is the way pass by reference and pass by value is used in the same manner by the caller. Imagine if this is not a copy constructor, but a function `void func(const foo &bar)` and `void func(foo bar)`, obviously there should be error, so is the same for this case, except that if the compiler does not generate error, the program might call the pass by value version, thus leading to incorrect behavior of copy constructor. – Amumu Dec 08 '11 at 20:34
2

complex(complex) is not a copy constructor. It's ill-formed, and should be rejected by compiler. There is no infinite recursion, because you simply cannot define a constructor like that.

A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).

A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-qualified) X and either there are no other parameters or else all other parameters have default arguments. A member function template is never instantiated to produce such a constructor signature.

Community
  • 1
  • 1
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
1

Answer to Java question since all other possible explanations are given:

//java code

public class Bar{
  private int foo;

  public Bar() { } // public no-args constructor
  public Bar(Bar b) { foo = b.foo; }  // copy constructor
}

In Java objects are references and not value objects like they are in C++. In C++ when you copy an object you create a copy of the object's state, internal variables etc. In Java it simply copies the reference. The object's state is not copied so there is actually no need to call the copy constructor like you do it in C++.

FailedDev
  • 26,680
  • 9
  • 53
  • 73