2012-06-26 18 views
22

Czy istnieje jakiś bezpieczny i standardowy, zgodny sposób traktowania tablicy w stylu C jako tablicy std :: bez kopiowania danych do nowej tablicy std ::?Traktuj tablicę Cstyle jako std :: array

To oczywiście nie kompiluje, ale jest efektem, którego chciałbym (moje rzeczywiste użycie jest bardziej skomplikowane, ale ta krótka próbka powinna pokazać, co chciałbym zrobić). Domyślam się, że reinterpret_cast będzie "działał", ale prawdopodobnie nie jest bezpieczny?

#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; 
} 

Wydaje się, że powinno być możliwe, ponieważ dane powinny być przechowywane identycznie.

edit: Aby być jasne, nie chcę, aby wyczyścić nową tablicę std ::, chcę odnieść się do istniejących danych jako jeden.

+1

kontenery STL zarządzania własną pamięć. Nie można utworzyć tablicy i zarządzać nią za pomocą tablicy, która została przydzielona w innym miejscu. – krammer

+2

Biorąc pod uwagę, że 'std :: array' i' std :: vector' oczekują na zarządzanie własną pamięcią, powinieneś być bardzo ostrożny przy używaniu 'reinterpret_cast' bez podejmowania kroków, aby upewnić się, że nie próbują usuwać danych, które nie są pod ich kontrolą. Ale na marginesie ... nie bój się "memcpy". W końcu to dość skuteczna rutyna. – Rook

+0

Ok dzięki. Chcę to zrobić bezpiecznie, a nie hackować, po prostu zastanawiałem się, czy to możliwe, to wszystko :) – jcoder

Odpowiedz

8

Nie możesz tego zrobić. Obiekt std::array jest agregatem i przechowuje własny blok danych (w przeciwieństwie do wskaźnika do bloku danych, który można łatwo ponownie przypisać). Więc nie ma sposobu na uniknięcie kopii wszystkich elementów. W języku C++ 11 jest to szczególnie ważne, ponieważ danych tablicy nie można przenieść, więc nie ma na przykład wydajnej funkcji std::swap.

+5

Rozumiem. Nie chcę tworzyć nowej tablicy std :: z własnymi danymi, chcę odwoływać się do istniejących danych tak, jakby były std :: array, ponieważ są prawdopodobnie tym samym układem. Jeśli można to zrobić bezpiecznie. Jestem pewien, że reinterpret_cast "hack" będzie "działał" ... – jcoder

+0

przegłosowany tak jak "przykro, że nie możesz tego zrobić bezpiecznie" to dobra odpowiedź na to pytanie, nawet jeśli nie to, na co liczyłem. – jcoder

7

Można użyć reinterpret_cast jednak pamiętać, że jest to brzydkie brudne siekać i nie powinno się robić coś takiego w swoim prawdziwym kodzie wydaniu:

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

Problemy mogą pojawić się, gdy wewnętrzna implementacja Zmiany std :: array (np. niektóre dodatkowe pola zostaną dodane w wersji debugowania STL, aby wykonać pewne sprawdzenia w czasie wykonywania). Wtedy ten kod zacznie się zawieszać bez żadnych komunikatów informacyjnych (ponieważ jest oparty na niejawnym założeniu, że obiekt std :: array i tablica C mają ten sam układ pamięci).

Jeśli zdecydujesz się pójść za brzydkie brudne hack, niemniej jednak przynajmniej dodać Sprawdź rozmiar kompilacji:

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

To będzie produkować błąd w przypadku rozmiaru std :: array <> przystanki pasujące do rozmiaru macierzy C (z powodu pewnych zmian w implementacji STL).

+0

Tak, mam to do "pracy". Zastanawiałem się, czy nie było sposobu, który nie byłby brzydkim, brudnym hackem :) dzięki – jcoder

+3

Nazwa 'reinterpret_cast' jest celowo brzydka, aby wyjaśnić, że używa się brzydkiego hacka. – MSalters

+0

Dzięki, dobra odpowiedź. Nie pójdę z brudnym hackem. W moim kodzie był tylko przypadek, w którym miałem stałą wielkość tablicy, więc chciałem użyć std :: array w całym kodzie, ale stary kod, którego nie mogę zmienić dał mi tablicę w stylu c. Nie zrobię tego za hack, ale byłoby miło móc zrobić coś efektywnego i popartego. – jcoder

15

Jak wspomniano w tym poście Is std::array<T, S> guaranteed to be POD if T is POD?

std::array<int, N> jest POD, a tym samym standardzie układ. O ile rozumiem standardowe wymagania dotyczące układu, oznacza to, że wskaźnik do obiektu jest identyczny ze wskaźnikiem dla pierwszego elementu. Ponieważ std :: array nie ma żadnych prywatnych/chronionych elementów (zgodnie z http://en.cppreference.com/w/cpp/container/array), powinno to być zgodne z pierwszym elementem w opakowanej tablicy. Zatem coś

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

jest moim zdaniem gwarantowane do pracy w standardzie. Muszę jednak przyznać, że czasami mam trudności z interpretacją standardowego języka, więc proszę, popraw mnie, jeśli się mylę.

Pozdrowienia Claas

+2

Myślę, że masz rację, ale chciałbym sprawdzić, czy array5 * p = reinterpret_cast < array5* > (& danych); ASSERT (p-> data() == &data); której właśnie chcemy – GameDeveloper

Powiązane problemy