2012-06-26 7 views
22

Есть ли какой-либо безопасный и стандартный способ лечения массива стилей C как std :: array без копирования данных в новый std :: array?Обработать C cstyle array как std :: array

Это явно не скомпилирует, но эффект, который мне бы хотелось (мое реальное использование сложнее, но этот короткий образец должен показать, что я хотел бы сделать). Я полагаю, что reinterpret_cast «работает», но, вероятно, небезопасен?

#include <array> 

int main() 
{ 
    int data[] = {1, 2, 3, 4, 5}; 

    // This next line is the important one, treating an existing array as a std::array 
    std::array<int, 5>& a = data; 
} 

Похоже, что это должно быть возможным, поскольку данные должны храниться одинаково.

Редактировать: Чтобы быть ясным, я не хочу очищать новый массив std ::, я хочу ссылаться на существующие данные как на один.

+1

STL контейнеры управлять своей памятью. Вы не можете создать массив и управлять им каким-либо массивом, который вы выделили в другом месте. – krammer

+2

Учитывая, что 'std :: array' и' std :: vector' рассчитывают управлять собственной памятью, вы должны быть очень осторожны в использовании 'reinterpret_cast', не предпринимая шагов, чтобы гарантировать, что они не пытаются и не удаляют данные, которые не являются под их контролем. Но это в стороне ... не бойтесь «memcpy». В конце концов, это довольно эффективная рутина. – Rook

+0

Хорошо спасибо. Я хочу сделать это безопасно, не делаю взлома, мне просто интересно, возможно ли это все :) – jcoder

ответ

8

Вы не можете этого сделать. std::array является агрегатом и содержит собственный блок данных (в отличие от указателя на блок данных, который можно легко переназначить). Таким образом, нет способа избежать копирования всех элементов. В C++ 11 это особенно важно, потому что данные массива не могут быть перемещены, поэтому нет эффективной функции std::swap, например.

+5

Я это понимаю. Я не хочу создавать новый std :: array со своими собственными данными, я хочу ссылаться на существующие данные, как если бы это был std :: array, поскольку они, вероятно, совпадают с макетом. Если можно сделать это безопасно. Я уверен, что reinterpret_cast «взломать» будет «работать» ... – jcoder

+0

все равно «жаль, что вы не можете сделать это безопасно» - хороший ответ на вопрос, даже если не то, на что я надеялся. – jcoder

7

Вы можете использовать reinterpret_cast, однако обратите внимание, что это некрасивый грязный хак, и вы не должны делать что-то подобное в вашем реальном коде выпуска:

std::array<int, 5> &a = reinterpret_cast<std::array<int, 5>&>(data); 

Проблемы могут возникнуть, если внутренняя реализация std :: array (например, некоторые дополнительные поля будут добавлены в отладочную версию STL для выполнения некоторых проверок времени выполнения). Тогда этот код начнет сбой без каких-либо информационных сообщений (поскольку он основан на неявном предположении, что объект std :: array и массив C имеют одинаковый макет памяти).

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

C_ASSERT(sizeof(a) == sizeof(data)); 

Это приведет к ошибке в случае, если размере станда :: массив <> остановок сопоставляя размер вашего массива C (из-за некоторых изменений в реализации STL).

+0

Да, я получил это, чтобы «работать». Я просто задавался вопросом, был ли способ, который не был уродливым грязным хаком :) спасибо – jcoder

+3

Имя 'reinterpret_cast' намеренно уродливо, чтобы прояснить, что используется уродливый хак. – MSalters

+0

Спасибо, хороший ответ. Я не пойду с грязным взломом. В моем коде был только случай, когда у меня был массив фиксированного размера, поэтому я хотел использовать std :: array в моем коде, но старый код, который я не могу изменить, дал мне массив c-стиля. Я не буду разбираться в этом, но было бы неплохо сделать что-то эффективное и поддерживаемое. – jcoder

15

Как обсуждалось в этом посте Is std::array<T, S> guaranteed to be POD if T is POD?

std::array<int, N> является СТРУЧОК и, следовательно, стандартное расположение. Насколько я понимаю стандартные требования к макету, это означает, что указатель на объект идентичен указателю на первый элемент. Поскольку std :: array не имеет частных/защищенных членов (в соответствии с http://en.cppreference.com/w/cpp/container/array), это должно совпадать с первым элементом в обернутом массиве. Так что-то вроде

reinterpret_cast< std::array<int, 5>* >(&data)

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

С уважением Claas

+2

Я думаю, что вы правы, но я бы проверял, что array5 * p = reinterpret_cast < array5* > (& data); ASSERT (p-> data() == &data); Это то, что мы, наконец, хотим – GameDeveloper