Параметр Const в конструкторе вызывает стековый поток - PullRequest
0 голосов
/ 29 мая 2010

Я обнаружил это странное поведение в компиляторе VS2005 C ++. Вот ситуация:

Я не могу опубликовать код, но ситуация очень проста.

Вот исходный код: он отлично работает

class Foo {
     public:
     Foo(Bar &bar) { ... }
}

Реализация конструктора хранит ссылку, настраивает некоторые элементы ... на самом деле ничего особенного.

Если я изменю код следующим образом:

class Foo {
     public:
     Foo(const Bar &bar) { ... }
}

Я добавил квалификатор const к единственному параметру конструктора.

Он компилируется правильно, но компилятор выдает предупреждение о том, что подпрограмма Foo :: Foo вызовет переполнение стека (даже если путь выполнения не создает никакого объекта Foo); эффективно это происходит.

Итак, почему код без параметра const работает идеально, а код с квалификатором const вызывает переполнение стека? Что может вызвать это странное поведение?

Ответы [ 3 ]

4 голосов
/ 29 мая 2010

Попробуйте использовать ключевое слово explicit?

Я предполагаю, что с const вы объявляете автоматическое преобразование из Bar в Foo; и если у вас уже есть аналогичное автоматическое преобразование из Foo в Bar, то переполнение?

2 голосов
/ 29 мая 2010

Единственный способ для этого вызвать переполнение стека (кроме ошибки в компиляторе, которая, за мои 15 лет работы с C ++, я обнаружил редкую по сравнению с моими собственными ошибками), заключается в том, что Foo(const Bar&) создает Foo объект, передающий его Bar объект . Подобные ошибки могут быть тонкими и их трудно найти, посмотрев на код.

Но если у вас VS2005, у вас под рукой довольно хороший отладчик. Поместите точку останова в этот конструктор, запускайте программу до тех пор, пока вы не достигнете точки останова, затем запускайте снова, пока вы не достигнете точки останова во второй раз. Изучение стека покажет вам, как это происходит.

Если не каждый вызов этого конструктора вызовет переполнение стека, вы можете добавить этот код:

namespace { unsigned int recursion_detector = 0; }

Foo::foo(const Bar& bar)
{
  if(recursion_detector++)
    ++recursion_detector; // meaningless code just to put a breakpoint here
  // rest of constructor code
}

и поставьте точку останова в указанной строке, которая будет достигнута, когда произойдет рекурсия.

0 голосов
/ 29 мая 2010

Вы можете изменить параметр с const Bar & bar на const Bar * bar. Он будет работать нормально, вам просто нужно изменить способ управления панелью параметров (от ссылки к указателю).

Инициализация объекта будет выглядеть примерно так:

Bar mybar;

...

Foo myfoo(&mybar);


class Foo {
     public:
     Foo(const Bar *bar) { ... }
};

Это не так уж плохо ...

...