2015-07-03 32 views
5

Mam tablicę (wskaźniki do) tablic o różnych długościach, które nauczyłem mogłem zdefiniować za pomocą literałów złożonych:Clang narzeka: „wskaźnik jest inicjowany przez tablicy tymczasowej”

const uint8_t *const minutes[] = { 
    (const uint8_t[]) {END}, 
    (const uint8_t[]) {1, 2, 3, 4, 5 END}, 
    (const uint8_t[]) {8, 9, END}, 
    (const uint8_t[]) {10, 11, 12, END}, 
    ... 
}; 

gcc akceptuje tę właśnie dobrze, ale clang mówi: pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression. Co to znaczy? Kod wydaje się być do pracy, ale znowu, wiele rzeczy wydaje się do pracy, gdy wskazują na pamięć, która nie jest już przydzielona. Czy jest to coś, o co muszę się martwić? (Ostatecznie naprawdę potrzebuję go tylko do pracy z gcc.)

Aktualizacja: Coś podejrzanego dzieje się. Mówi here że:

Compound literals yield lvalues. This means that you can take the address of a compound literal, which is the address of the unnamed object declared by the compound literal. As long as the compound literal does not have a const-qualified type, you can use the pointer to modify it.

`struct POINT *p; 
    p = &(struct POINT) {1, 1}; 

Ten przykładowy kod wydaje się, że robi dokładnie to, co usiłuję zrobić: wskaźnik do czegoś zdefiniowanej przez związek dosłownym. Czy komunikat o błędzie klang jest wiarygodny? Czy to wskaże na nieprzydzieloną pamięć po kompilacji z klangiem lub gcc?

Aktualizacja 2: Znaleziono niektóre documentation: „W C dosłownym związek wyznacza anonimowego obiektu ze statycznym lub automatycznym czas przechowywania W C++, związek dosłowne oznacza tymczasowy obiekt, który tylko żyje aż do końca. jego pełnego wyrażenia "Tak więc wydaje się, że klang ma rację, ostrzegając o tym, a gcc prawdopodobnie również powinien, ale nie, nawet z -Wall -Wextra.

Nie mogę zgadnąć, dlaczego użyta funkcja C została usunięta z języka C++ i nie podano eleganckiego alternatywnego sposobu osiągnięcia tego samego.

+0

Czy kompilacji z Flaga '-W' przy użyciu gcc?Może się pojawić, jeśli nie jesteś – GeoffreyB

+0

Tak. -Wall -Wextra, która jest podobno tą samą rzeczą. – Josh

+0

próbowałeś usunąć niepotrzebne '(const uint8_t [])' na początku każdego wiersza? –

Odpowiedz

3

Cóż, dzyń ma rację, a odbywa się to w ten sposób:

namespace elements 
{ 
    const uint8_t row1[] = {END}; 
    const uint8_t row2[] = {1, 2, 3, 4, 5, END}; 
    ... 
} 
const uint8_t *const minutes[] = { 
    elements::row1, 
    elements::row2, 
    ... 
}; 

można myśleć bardziej C roztworu ++, jak przy użyciu std::tuple:

#include <tuple> 

constexpr auto minutes = std::make_tuple(
    std::make_tuple(), 
    std::make_tuple(1,2,3,4,5), 
    std::make_tuple(8,9,10)); 

#include <iostream> 
#include <type_traits> 
int main() { 
    std::cout << std::tuple_size<decltype(minutes)>::value << std::endl; 
    std::cout << std::tuple_size<std::remove_reference_t<decltype(std::get<1>(minutes))>>::value << std::endl; 
} 
+0

Dlaczego nie podoba mi się twoja pierwsza opcja: jest brudny. Jest podatny na literówki, a jeśli zmienię kolejność wierszy lub dodam wiersz później, trzeba zmienić wiele zmiennych, albo po prostu zostawić numery wierszy poza kolejnością. Mimo to wydaje się, że jest to najprostszy sposób na uzyskanie prawidłowej reprezentacji danych w pamięci. – Josh

+0

Będę musiał sprawdzić drugą opcję, ze std :: tuple i constexpr. Czuję się bardziej komfortowo z C niż C++ (jeśli nie zgadłeś - ale korzystam z niektórych bibliotek C++ dla tego projektu) i koduję wbudowany system z * malutką * pamięcią, więc nie chcę użyć dowolnej funkcji, jeśli nie wiem dokładnie, co dzieje się za zasłoną.(Tak, zdaję sobie sprawę z filozofii projektowej stojącej za C++ lub ogólnie OOP, jest to, że nie musisz * znać * wewnętrznej implementacji, ale ... :) – Josh

+0

@Josh Jeśli boisz się złego zamówienia - ty może używać 'BOOST_PP_ENUM' - patrz http://www.boost.org/doc/libs/1_39_0/libs/preprocessor/doc/ref/enum.html. – PiotrNycz

1

Cóż to znaczy, to wyrażenie

(const uint8_t[]) {1, 2, 3, 4, 5 END}, 

tworzy tymczasowy obiekt — tymczasowy, ponieważ nie ma żadnej nazwy, która może trwać poza wyrażeniem, którego jest częścią — który zostanie zniszczony pod koniec pełnej ekspresji, co oznacza to:

definiuje „pełny wyraz”, w tym momencie wszystkie tymczasowe obiekty dostanie zniszczony, W tablicy wskaźników minutes znajdują się wskaźniki wskazujące na zniszczone obiekty, dlatego kompilator ostrzega.

Nadzieję, że pomaga.

+0

Tak, podejrzewałam tyle. Więc co mam na ten temat zrobić? :) – Josh

+0

Najpierw zdefiniuj je jako tablicę. Albo lepiej przeprojektuj to. Spróbuj użyć 'std :: array'. – Nawaz

+0

Czy możesz podać przykład tego, co masz na myśli? Musi być na to sposób, który nie wymaga tworzenia dziesiątek indywidualnie nazwanych zmiennych, których tak naprawdę nie chcę lub zamierzam użyć ... prawda? Ta złożona metoda literałów była tą, którą dostałem z odpowiedzi tutaj na SO - czy to rzeczywiście jest złe? – Josh

2

aktualizacja: dzięki deniss za wskazanie luki w oryginalnym rozwiązaniu.

static constexpr uint8_t END = 0xff; 

template<uint8_t...x> 
const uint8_t* make() 
{ 
    static const uint8_t _[] = { x..., END }; 
    return _; 
} 

const uint8_t* const array[] = { 
    make<>(), 
    make<1, 2, 3, 4, 5>(), 
    make<8, 9>(), 
    make<10, 11, 12>() 
}; 
+0

Kompiluje to, chociaż powoduje, że kompilowana aplikacja jest większa i sprawia, że ​​zajmuje ona nieco więcej pamięci - nie jest idealna dla systemu wbudowanego. Jakiś pomysł, dlaczego tak jest? Nie jestem również pewien, co robi - jak rozumiem, statyczna zmienna powinna alokować przestrzeń, gdy będzie się utrzymywać między wywołaniami funkcji. Jak więc ta funkcja przydziela nową przestrzeń za każdym razem, gdy jest wywoływana? – Josh

+0

Generuje jedną funkcję statyczną dla różnych rzędów liczb. Każda funkcja statyczna będzie zawierała tablicę statyczną (i ukryty muteks). Kiedy mówisz więcej pamięci, ile mówimy? Po optymalizacji kilkaset bajtów może być warta wymiany w celu ułatwienia konserwacji. –

+0

Uwaga: dla tej samej liczby parametrów ta funkcja generuje tylko 1 tablicę (wypełnioną wartościami z pierwszego wywołania). – deniss