Ошибка «рекурсивная на всех путях управления» когда используется конструктор копирования и присутствует виртуальная функция

Ошибка ниже сбивает меня с толку. Вот небольшой фрагмент гораздо более сложного кода. Мне кажется странным, что только существование как шаблонного конструктора, так и виртуального метода вызывает ошибку, и только при инициализации объекта при копировании.

У кого-нибудь есть идея? Благодарю.

    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;

Следующая строка в main() является

      A a=c;

и это вызывает ошибку ниже, если обе линии отмечены // 1 а также // 2 присутствуют:

warning C4717: 'C::C' : recursive on all control paths, function will cause runtime stack overflow

Но когда следующее используется в main()нет ошибки:

      A a;
a=c;
}

4

Решение

То, что у вас есть, это мерзкое слияние копия elision и конструктор, который делает копию параметра.

Во-первых, давайте проясним недоразумение: A a = c; является не эквивалентно A a; a = c;, Первый вызывает копию ctor, второй вызывает оператор присваивания. Смотрите сами, используя этот пример кода.

Конструктор A::A<T>(T) может сделать копию T всякий раз, когда это называется. К сожалению, если вы называете это с помощью A параметр (или в вашем примере C, который является A), параметр попытается скопировать сам, который вызывает A::A<T>(T) снова, который копирует себя снова и снова … до тех пор, пока стек не переполнится.

Почему этого не происходит, когда у вас нет virtual void f() в B? Это побочный эффект исключения из копирования, который зависит от реализации. Наличие виртуального метода могло бы быть достаточным для Visual Studio, чтобы решить не исключать копию, но в любом случае вы не должны зависеть от этого. Вот почему ты Настоятельно рекомендуется не иметь видимых побочных эффектов для копирующих ctors.

Если вы искали решение, вы можете удалить копию, изменив A::A<T>(T) взять ссылку, как A::A<T>(T&), Еще лучше возьми const T& потому что это помогает гарантировать отсутствие побочных эффектов в ctor (так как вы не можете изменить T).

4

Другие решения

    A a=c; // this results in A::A(C c) template constructor instantiation.

После этого это рекурсия, так как чтобы сделать копию, вам нужно сделать копию, вам нужно сделать копию …. 🙂

Для правильного использования обратитесь этот.

1

По вопросам рекламы [email protected]