2012-03-09 3 views
22

В this вопросе, Говард Hinnant сказалПочему не рекомендуется использовать рекурсивное наследование для реализации std :: tuple?

Некоторых реализация станд :: кортеж использовать рекурсивное наследование. Но хорошие - нет. ;-)

Может кто-то пролить свет на это?

+1

Возможно, это связано с неэффективной пересылкой аргументов? –

+0

, вероятно, было бы полезно, если бы кто-то мог определить разницу между этими хорошими и некоторыми. – PlasmaHH

+0

@ Чередование: я бы подумал, что вложение будет иметь дело с этим, - но опять же, я должен признать, что я * имел * запущен в компиляторы, которые наотрез решили прекратить встраивание на глубину более 3 или 4. – Hurkyl

ответ

29

A non-recursive implementation имеет лучшую производительность при компиляции. Верьте или нет, в сильно используемом библиотечном средстве, таком как std::tuple, как оно реализовано, может повлиять (к лучшему или худшему), время компиляции, которое видит клиент. Рекурсивные реализации имеют тенденцию создавать моменты компиляции, которые являются линейными по глубине рекурсии (или могут быть еще хуже).

Это влияет не только на создание самого кортежа. std::get<I>(tuple), например, возьмет линейное количество времени компиляции для одной реализации и постоянное количество времени компиляции для другой реализации. Это влияние может быстро ухудшаться (или нет) при работе с кортежами кортежей. То есть рекурсивная реализация может привести к времени компиляции O (N^2), тогда как нерекурсивная реализация все еще O (1).

Fwiw, реализация libC++ выдает объекты в порядке, указанном клиентом, но оптимизирует пространство для пустых компонентов с использованием средства оптимизации пустого базового класса компилятора.

+2

Этот вопрос (и ваш ответ) побудил меня исследовать реализацию нерекурсивного кортежа. Я написал сообщение об этом: http://mitchnull.blogspot.com/2012/06/c11-tuple-implementation-details-part-1.html. Я был бы признателен, если бы вы потратили немного времени, чтобы прочитать его и указать на любые ошибки. Спасибо – mitchnull

+1

Я использовал реализацию Howards для улучшения моей маленькой программы. Я также включил [index tricks] (http://stackoverflow.com/a/20045842/2712726) в тесты, чтобы улучшить tuple_element относительно времени компиляции и размера исполняемого файла. К моему удивлению, все стало не лучше, а хуже. Я использую gcc 4.8.2. Создает ли новейший gcc что-то, что оптимизировало рекурсию шаблона хвостового хвоста? Или упомянутые трюки работают только для угловых случаев? Есть ли какой-нибудь пример или история успеха, доказывающая эффективность оптимизации? –

3

Я не помню, как Андрей Александреску начал вести переговоры в 2012 году ровно, но он рассказал об этом, и одним из пунктов, которые он упомянул, была макет памяти. Если у меня есть std::tuple<int, short, char, char>, он будет в памяти как char, short, int, и этот макет возьмет (в моей системе) 4 байта больше, чем если бы они были выложены как int, short, char. R. Martinho Fernandes напомнил мне, что лучше всего сделать это в памяти в порядке, который сводит к минимуму заполнение, которое не является ни заказом, указанным , ни обратного порядка. (Наивное наследование делает обратный порядок).

Если я пишу std::tuple<int, char, short, char>, кортеж, который работает по наивному наследованию, поместил бы их в порядке char, short, int в память, используя 3 байта заполнения, когда оптимальный имеет нулевые байты заполнения. (Либо int, short, char, char, либо char, char, short, int).

Предполагая, что я прав, что речь идет о заполнении, тогда Р. Мартиньо Фернандес said «[мой аргумент] не исключает использования рекурсивного наследования для реальной реализации в оптимальном порядке». укажите, что naïve Наследование плохое.

(Порядок в памяти делает не означает, что get<0> даст другой объект, и Р. Martinho Fernandes правильно отмечает, что порядок должен быть невидимым для пользователя. Тем не менее, это были точки, как я напомнил от события GoingNative.)

Видеоролик находится по адресу http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Variadic-Templates-are-Funadic, а слайды - http://ecn.channel9.msdn.com/events/GoingNative12/GN12VariadicTemplatesAreFunadic.pdf.

+0

Вы должны сказать, что говорить. –

+0

Где он говорит о чем-либо еще в своем комментарии? –

+0

Почему-то я думал, что Йоханнес говорил о GoingNative, не знаю почему я так думал. –

2

Одна из причин не использовать цепочку базовых классов состоит в том, что не существует цепочки задействованных конструкторов: аргументы непосредственно перенаправляются в соответствующий подобъект. Кроме того, кажется, что нерекурсивная реализация значительно снижает нагрузку на компилятор и создает намного меньше [внутренних] символов. Не говоря уже о том, что на самом деле проще не цепочки базовых классов.

Смежные вопросы