The error below is confusing me. Here is a short piece of a much more complicated code. It appears strange to me, that only the existence of both a templated constructor and a virtual method cause an error, and only when copy-initializing an object.
Does anyone have an idea? Thanks.
class A
{
long *p;
public:
A():p(0)
{
}
template<class T>
A(T val):p(val)// 1
{
}
operator long*()
{
return p;
}
};
class B
{
virtual void f()// 2
{
}
};
class C : public A, public B
{
};
void main()
{
C c;
The next line in main()
is
A a=c;
and this triggers the error below if both the lines marked // 1
and // 2
are present:
warning C4717: 'C::C' : recursive on all control paths, function will cause runtime stack overflow
But when the following is used in main()
, there is no error:
A a;
a=c;
}
What you have is a nasty confluence of copy elision and a constructor that makes a copy of the parameter.
First, let's clear up a misunderstanding: A a = c;
is not equivalent to A a; a = c;
. The first calls the copy ctor, the second calls the assignment operator. See for yourself using this code sample.
The constructor A::A<T>(T)
could make a copy of T
whenever it is called. Unfortunately, if you call it using an A
parameter (or in your example C
, which is-a A
), the parameter will attempt to copy itself, which calls A::A<T>(T)
again, which copies itself again, and again... until stack overflow.
Why doesn't this happen when you don't have the virtual void f()
in B
? This is a side effect of copy elision, which is an implementation-dependent feature. Having the virtual method there might have been enough for visual studio to decide not to elide the copy, but in any case you shouldn't depend on it. This is why you are strongly advised not to have observable side-effects for copy ctors.
Just in case you were looking for a solution, you can remove the copy by changing A::A<T>(T)
to take a reference, like A::A<T>(T&)
. Even better, take a const T&
because this helps ensure that there are no side effects in the ctor (as you can't modify the T
).
A a=c; // this results in A::A(C c) template constructor instantiation.
After that it is recursion since to make a copy, you need to make a copy, you need to make a copy.... :)
For proper usage refer this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With