У меня есть программа (полный код here), который покидает вокруг 46000th итерации:Программа на C++ выходит без ошибок. Как отлаживать?
{
PROCESSER<MONO_CONT> processer;
c_start = std::clock();
for (unsigned long long i = 0; i < iterations; i++) {
BloombergLP::bdlma::BufferedSequentialAllocatoralloc(pool, sizeof(pool));
MONO_CONT* container = new(alloc) MONO_CONT(&alloc);
container->reserve(elements);
processer(container, elements);
}
c_end = std::clock();
std::cout << (c_end - c_start) * 1.0/CLOCKS_PER_SEC << " ";
}
В этом случае MONO_CONT
является vector<string, scoped_allocator_adaptor<alloc_adaptor<BloombergLP::bdlma::BufferedSequentialAllocator>>>
. Я понимаю, что scoped_allocator_adaptor
будет следить за тем, чтобы поставляемый распределитель использовался для распределения для передаваемых строк, тем самым гарантируя, что строки будут освобождены в конце каждой итерации цикла (избегая предложения 1201ProgramAlarm для проблемы). alloc_adapter
- это всего лишь оболочка, чтобы распределители Bloomberg соответствовали правильному интерфейсу.
PROCESSER
является следующим шаблонным функтором, который просто выполняет основные операции шаблонного контейнера, MONO_CONT
:
template<typename DS2>
struct process_DS2 {
void operator() (DS2 *ds2, size_t elements) {
escape(ds2);
for (size_t i = 0; i < elements; i++) {
ds2->emplace_back(&random_data[random_positions[i]], random_lengths[i]);
}
clobber();
}
};
Обратите внимание, что escape
и clobber
просто какой-то магия, что не делать ничего другого, кроме поражения оптимизатора (см this talk если вы заинтересованы). random_data
- это всего лишь массив из char
с мусором. random_positions
определяет действительные индексы на random_data
. random_lengths
определяет допустимую длину строки (не выходит из конца данных мусора), начиная с соответствующей позиции в random_positions
.
У меня есть подобный код, который работает точно такое же число итераций, и не подведет:
{
PROCESSER<MONO_CONT> processer;
c_start = std::clock();
for (unsigned long long i = 0; i < iterations; i++) {
BloombergLP::bdlma::BufferedSequentialAllocator alloc(pool, sizeof(pool));
MONO_CONT container(&alloc);
container.reserve(elements);
processer(&container, elements);
}
c_end = std::clock();
std::cout << (c_end - c_start) * 1.0/CLOCKS_PER_SEC << " ";
}
Основное различие между этими двумя отрывками является то, что в первом, я new
ИНГ контейнер в распределитель, а затем передать распределитель в контейнер, опираясь на уничтожение распределителя для освобождения всей памяти контейнера (без фактического вызова деструктора самого контейнера). Во втором фрагменте я разрешаю более естественное уничтожение контейнера, выходя из области видимости в конце каждой итерации цикла.
Я строю это с Clang, работая в контейнере Docker на Debian. Предложения о том, что может быть проблемой, и как я могу начать отлаживать это?
В первом примере используется 'placement-new'. Итак, где явный вызов деструктора? https://isocpp.org/wiki/faq/dtors#placement-new – PaulMcKenzie
@PaulMcKenzie Насколько я знаю, определено, что он не вызывает деструктор, учитывая, что деструктор распределителя очищает память, и я никогда не получаю доступ к контейнер после того, как его память удалена.Взгляните на последние 3 параграфа главы 3 для более подробной информации о том, почему я это делаю: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0089r0.pdf – GBleaney
Если вы обеспокоены эффективностью распределителя, подумайте о создании объекта «MONO_CONT» за пределами цикла, «clear» («) после каждой итерации, а затем« reserve() »достигли отметки о высокой воде и редко нуждаются в каком-либо распределении , –