2013-03-22 2 views
1

Я хочу хранить ограниченное количество элементов в контейнере. Я не хочу использовать массив, потому что хочу избежать ненужных вызовов конструктора объектов. Я не хочу использовать std::vector из-за неявного вызова malloc (я хочу минимизировать доступ к куче для максимальной когерентности кеша).Обход правил C++ с строгим сглаживанием

Поэтому я решил определить свой собственный контейнер, что-то вроде этого:

template<typename T, size_t capacity> class my_array { 
    private: 
    char buffer[sizeof(T)*capacity]; 
    ... 
    public: 
    T& operator[](size_t i) { return *(T*)&buffer[i*sizeof(A)]; } 
    ... 
}; 

Но когда я пытаюсь на самом деле использовать этот контейнер, я получаю предупреждение компилятора о нарушении правил строгого сглаживания. Я читал о строгом сглаживании, и я понимаю, почему оптимизация компилятора может привести к разрыву вышеуказанного кода.

Как мне обойти это?

Странно, что мой компилятор не жалуется на мой собственный класс object_pool, который, среди прочего, я использую для пользовательского распределителя для моих ассоциативных структур данных STL. Этот класс выглядит ужасно похожим на вышеизложенное (использует char[] и делает аналогичный перевод). Я не могу понять, какая разница между ними.

+0

Не можете ли вы просто использовать 'std :: array'? Или 'std :: tr1 :: array' или' boost :: array' у вас нет поддержки C++ 11? – juanchopanza

+0

У меня нет поддержки C++ 11. Даже если бы я это сделал ... другое требование, которое я имею, это то, что я не хочу называть конструктор 'T' немедленно, по соображениям производительности.Я должен был упомянуть это требование, я отредактирую свой пост. – dshin

ответ

1

Если вы не собираетесь использовать std:array затем

char buffer[sizeof(T)*capacity]; 

, вероятно, следует

T buffer[capacity] 

Вот почему шаблоны поддержки typename с в первую очередь.

+0

Есть ли способ сделать это, не вызывая вызов конструктора 'T'? – dshin

+0

№ Это делает его намного сложнее. – dmckee

1

Используйте std::aligned_storage, если вы не хотите инициализировать объекты так, как требуется std::array. Вероятно, вы столкнетесь с проблемой выравнивания, поскольку ваша структура может быть привязана к нечетному адресу.

Алиасинг с массивом char для использования в качестве хранилища должен быть прекрасным, я не уверен, о чем идет речь в вашем компиляторе. Это действительно минимальный тест?

+0

re "Слияние с массивом символов, чтобы использовать его как хранилище, должно быть хорошо". для чисто формального массив символов здесь не должен быть соответствующим образом выровнен для T. это не динамически выделенный массив. на практике, если OP имеет виртуальную функцию или что-то в этом роде, то массив не должен находиться в начале структуры, поэтому, даже если структура правильно выровнена, массив не должен быть. –

+0

Если вы добавите экземпляр 'my_array ', а затем используйте оператор' [] ', то да, это минимальный тестовый файл. Я тоже смущен, потому что я думал, что существует исключение для 'char'. – dshin

+0

К сожалению, не поддерживайте C++ 11, поэтому не можете использовать std :: aligned_storage. – dshin

0

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

я заменил

T& operator[](size_t i) { return *(T*)&buffer[i*sizeof(A)]; } 

с

T* operator[](size_t i) { 
    if (...) { 
    return (T*)&buffer[i*sizeof(A)]; 
    } 
    return NULL; 
} 

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

Мне было бы любопытно, сможет ли кто-нибудь объяснить, что именно здесь происходит в голове компилятора. Я использую gcc 4.4.3.

+0

У старых компиляторов есть ошибки. Почему бы и нет. – Potatoswatter

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