2012-12-04 16 views
6

Załóżmy, że mam std::array<T, n> i chcę pobrać odwołanie do jej zawartości (tj. Do nienaświetlonych elems element tablicy).Odwzoruj tablicę `T (&) [n]` na zawartość `std :: array <T, n>`

Zaskoczyło mnie, że std::array<T, n>::data() zwraca T *, a nie T (&)[n], więc wydaje się, że potrzebny jest jakiś rzut. Mogę napisać:

std::array<int, 5> arr; 
int (&ref)[5] = *reinterpret_cast<int (*)[5]>(arr.data()); 

Jednak to wygląda brzydko i potencjalnie niebezpieczne. Czy jest to uzasadniony (dobrze zdefiniowany) kod i czy istnieje lepszy sposób na zrobienie tego?

+0

Proponuję szablon szablonu funkcji "constexpr" wielokrotnego użytku, aby ukryć tę brzydotę. –

+0

Narożny przypadek będzie miał rozmiar 0, w którym to przypadku prawa strona będzie niezdefiniowana, chociaż w tym szczególnym przypadku lewa strona nie będzie się nawet kompilować (tj. Nie można zadeklarować tablicy 0 elementów) –

+0

Użycie 'arr.size()' zamiast '5' byłoby mniej kruche (to' constexpr' i może być używane jako rozmiar tablicy). Nie jestem pewien, czy obsada jest dobrze zdefiniowana. –

Odpowiedz

3

Standard nie przewidują podstawowym zastosowaniem array, ale jeśli używa int[5] jako podstawowej reprezentacji, to dla tej realizacji tylko twoja obsada byłaby (non-przenośnie) legalne. W przypadku każdej innej reprezentacji podstawowej naruszasz zasady ścisłego aliasingu i wprowadzasz niezdefiniowane zachowanie.

Zamiast próbować zwrócić tablicę jako tablicę, możesz użyć par iteratorów do wyznaczenia zakresu, który cię interesuje, poprzedzając standardową biblioteką?

+0

Elementy są przechowywane w sposób ciągły (23.3.2.1p1), więc czy nie powinno być możliwe alias jako tablica? – ecatmur

+0

@egatmur Tylko wtedy, gdy pierwotny typ bazowy w tablicy "tablica" jest typem, który też rzucasz - w przeciwnym razie jest to niezdefiniowane zachowanie spowodowane nieprawidłowym wygładzaniem oryginalnego typu. Rozważmy kompilator, który zdecydował się zaimplementować przestrzeń jako "aligned_storage" lub coś innego niż rzeczywistą tablicę. –

+0

@MarkB: Ale element 'data() 'musi zapewniać dostęp do tych danych jako * tablica * dynamiczna, która ma taki sam układ pamięci, jak zwykła tablica. Skłaniam się do stwierdzenia, że ​​prawie zawsze bezpieczne jest wykonywanie tego (w przeciwnym razie strasznego) obsady. To znaczy. 'data()' już zastępuje wewnętrzną reprezentację w * zgodnym * tablicowym * –

0

Tablica w C++ jest wadliwym typem (tutaj mówię o tablicy w stylu c, a nie std::array). Powodem tego jest to, że rozmiar tablicy nie jest przechowywany w dowolnym miejscu w pamięci, jest znany tylko podczas kompilacji. W prawo, gdy rzutujesz tablicę na inny typ (zwykle na wskaźnik), rozmiar tablicy zostaje utracony.

Teraz można zauważyć, że nie można wykonać odwrotnego rzutowania, ponieważ nie ma możliwości, aby kompilator znał rozmiar tablicy, patrząc tylko na wskaźnik do pierwszego elementu. Jak już sugerowano, zamiast tego można użyć pary iteratorów.

Powiązane problemy