Причина, по которой мне так нравится Rcpp, заключается в том, что я не всегда понимаю, как думает R Core, а с Rcpp, чаще всего, мне это не нужно.
Говоря философски, вы пребываете в состоянии греха в отношении функциональной парадигмы, которая пытается гарантировать, что каждое значение появляется независимо от любого другого значения; изменение одного значения никогда не должно вызывать видимого изменения другого значения, как это происходит с указателями, разделяющими представление в C.
Проблемы возникают, когда функциональное программирование сигнализирует малому кораблю отойти с дороги, а малый корабль отвечает: «Я - маяк». Внесение длинной серии небольших изменений в большой объект, который вы хотите обработать, тем временем помещает вас прямо на территорию маяка.
В C ++ STL push_back()
это образ жизни. Он не пытается быть функциональным, но он действительно пытается приспособить общие идиомы программирования эффективно .
Проявив некоторую смекалку за кулисами, вы можете иногда договориться о том, чтобы ступить в каждый мир одной ногой. Файловые системы на основе моментальных снимков являются хорошим примером (которые произошли от таких концепций, как объединенное монтирование, которое также соединяет обе стороны).
Если бы R Core захотел это сделать, базовое векторное хранилище могло бы функционировать как объединенное монтирование. Одна ссылка на хранилище векторов может быть действительной для индексов 1:N
, а другая ссылка на то же хранилище действительна для индексов 1:(N+1)
. Там может быть зарезервированное хранилище, на которое еще не ссылается что-либо, кроме удобного для быстрогоpush_back()
. Вы не нарушаете функциональную концепцию при добавлении за пределы диапазона, который любая существующая ссылка считает допустимой.
Постепенно добавляя строки, вы исчерпываете зарезервированное хранилище. Вам нужно будет создать новые копии всего, с умножением объема хранилища на некоторое приращение. Реализации STL, которые я использовал, имеют тенденцию умножать объем памяти на 2 при расширении распределения. Я думал, что прочитал в R Internals, что есть структура памяти, в которой объем хранилища увеличивается на 20%. В любом случае операции роста происходят с логарифмической частотой относительно общего числа добавленных элементов. На амортизированной основе это обычно приемлемо.
Что касается закулисных трюков, я видел и похуже. Каждый раз, когда вы push_back()
добавляете новую строку в фрейм данных, необходимо копировать структуру индекса верхнего уровня. Новая строка может добавляться к общему представлению, не влияя на старые функциональные значения. Я даже не думаю, что это сильно усложнит сборщик мусора; поскольку я не предлагаю, что push_front()
все ссылки являются префиксными ссылками на переднюю часть выделенного векторного хранилища.
append()
[который, вероятно, следует назвать insert] илиc()
добавлять элементы в конец списка, но здесь это вам не поможет.