2009-09-23 19 views
6

Jestem niejasny o następujących.Pytanie dotyczące przechowywania macierzy w std :: vector w C++

Po pierwsze, ten kod kompiluje grzywny:

#include <vector> 

typedef struct{ 
    int x1,x2,x3,x4; 
} ints; 

typedef std::vector<ints> vec; 

int main(){ 
    vec v; 
    ints a = {0,1,2,3}; 
    v.push_back(a); 
} 

Poniższy kod jest blisko identyczne:

#include <vector> 

typedef std::vector<int[4]> vec; 

int main(){ 
    vec v; 
    int a[4] = {0,1,2,3}; 
    v.push_back(a); 
} 

ale rzuca niezwykle wyjście błędu długość będę zawierać na końcu. Dlaczego kompilator traktuje te dwa programy w tak różny sposób? To zdecydowanie nie jest intuicyjne.

Tutaj jest błąd kompilatora, który jest generowany w systemie, który jest przy użyciu g ++ skompilować:

[[email protected] Test]$ g++ test2.cpp -o test2 
In file included from /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/i586-redhat-linux/bits/c++allocator.h:34, 
       from /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/allocator.h:48, 
       from /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/vector:62, 
       from test2.cpp:2: 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = int [4]]’: 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/stl_vector.h:737: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = int [4], _Alloc = std::allocator<int [4]>]’ 
test2.cpp:9: instantiated from here 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/ext/new_allocator.h:105: error: ISO C++ forbids initialization in array new 
In file included from /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/vector:69, 
       from test2.cpp:2: 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = int [4], _Alloc = std::allocator<int [4]>]’: 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/stl_vector.h:741: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = int [4], _Alloc = std::allocator<int [4]>]’ 
test2.cpp:9: instantiated from here 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/vector.tcc:306: error: array must be initialized with a brace-enclosed initializer 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/stl_vector.h:741: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = int [4], _Alloc = std::allocator<int [4]>]’ 
test2.cpp:9: instantiated from here 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/vector.tcc:312: error: invalid array assignment 
In file included from /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/i586-redhat-linux/bits/c++allocator.h:34, 
       from /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/allocator.h:48, 
       from /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/vector:62, 
       from test2.cpp:2: 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::destroy(_Tp*) [with _Tp = int [4]]’: 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/vector.tcc:353: instantiated from ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = int [4], _Alloc = std::allocator<int [4]>]’ 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/bits/stl_vector.h:741: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = int [4], _Alloc = std::allocator<int [4]>]’ 
test2.cpp:9: instantiated from here 
/usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++/4.4.1/ext/new_allocator.h:115: error: request for member ‘~int [4]’ in ‘* __p’, which is of non-class type ‘int [4]’ 

Odpowiedz

6

pod maską to robi zadanie i że nie jest zdefiniowana dla tablic.

odpowiedniej części tego błędu jest

instancja stąd /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/c++ /4.4.1/bits/vector.tcc:306: błąd: tablica musi zostać zainicjalizowana za pomocą inicjalizatora z nawiasami klamrowymi /usr/lib/gcc/i586-redhat-linux/4.4.1/../../ ../../include/c++/4.4.1/bits/stl_vector.h:741: utworzono z 'void std :: vector < _Tp, _Alloc> :: push_back (const _Tp &) [z _Tp = int [4 ], _Alloc = std :: allocator] 'test2.cpp: 9: utworzona stąd /usr/lib/gcc/i586-redhat-linux/4.4.1/../../../../include/ C++/4.4.1/bits/vector.tcc: 312: błąd: nieprawidłowe przypisanie tablicy

+1

Sposób działania tych błędów szablonów polega na tym, że kompilator próbuje utworzyć instancję podanego typu - następnie kompiluje wynikowy kod. Gdy wystąpi błąd, próbuje dać ci pojęcie, w jaki sposób kod znalazł problem związany z kodem, który napisałeś, i zakłada, że ​​znasz kod źródłowy szablonu, abyś mógł zrozumieć błąd. Musisz trochę zignorować wszystkie komentarze "tworzone od", aby znaleźć problem. –

+0

Słyszałem, że C++ 0x (aka C++ 1x, w tym tempie) może skończyć się bardziej przyjaznymi błędami na tym sprzęcie. – Brian

+2

@Brain prawdopodobnie nie. Ulepszone błędy były zależne od koncepcji, które zostały usunięte z C++ 0x. –

2

Minęło trochę czasu, odkąd użyłem C++, ale uważam, że głównym problemem, z którym się spotykacie, jest to, że macierze nie mają wymaganej semantyki, aby dobrze się dogadać z std::vector<>. Nie mam przy sobie mojego egzemplarza Stroustrup, albo dałbym ci referencje.

6

Wypróbuj boost::array zamiast zwykłych tablic. Zapewnia interfejs zgodny ze standardem STL wokół macierzy o ustalonych rozmiarach, dzięki czemu można go używać w kontenerach STL. Dodatkowo implementuje sprawdzanie granic (boost::array::at).

#include <boost/array.hpp> 
#include <vector> 

typedef std::vector< boost::array<int, 4> > vec; 
int main(){ 
    vec v; 
    boost::array<int, 4> va = {0,1,2,3}; 
    v.push_back(va); 
} 
+2

Alternatywnie, użyj 'std :: tr1 :: array' (który jest taki sam jak Boost one, ale ISO-standaryzowany), jeśli jest on dostępny w twojej implementacji. –

11

error: ISO C++ forbids initialization in array new
error: array must be initialized with a brace-enclosed initializer
error: invalid array assignment
error: request for member ‘~int [4]’ in ‘* __p’, which is of non-class type ‘int [4]’

Aby zrozumieć jeden z błędów, wyobraź sobie, co następuje:

void main() { 
    int a[4] = {0,1,2,3}; 
    int b[4] = a; 
} 

W przeciwieństwie do:

typedef struct{ 
    int x1,x2,x3,x4; 
} ints; 

int main() 
{ 
    ints a; 
    ints b = a; 
} 

Albo nawet:

typedef struct{ 
    int x[4]; 
} ints; 

int main() 
{ 
    ints a; 
    ints b = a; 
} 

Szyfrów C/C++ nie można kopiować za pośrednictwem operatora przypisania, choć może to być tablica zawierająca tablice.
Więc łatwo naprawić to zrobić:

typedef struct{ 
     int x[4]; 
} ints; 

typedef std::vector<ints> vec; 

int main(){ 
     vec v; 
     ints a = { {0,1,2,3} }; 
     v.push_back(a); 
} 
2

Spróbuj użyć vector z vector zamiast.

+1

Myślę, że może istnieć uzasadniona chęć użycia wektora macierzy. (Ja sam prawdopodobnie nadużyłem wektora wektora, ponieważ nie wiedziałem o takich rzeczach jak boost :: array.) – UncleBens

1

Wymóg wartość typu T dla wszystkich pojemników STL w tym std::vector<T>, że T jest Assignable - ISO C++ 03 23,1 [lib.container.requirements]/4-5. Assignable jest zdefiniowany następująco:

Expression t = u , where t is of type T , and u is of type cvT , is valid, its return type is T& , and the post-condition is that t is equivalent to u .

Tablice nie spełniają tego wymogu, ponieważ nie można napisać:

int a[2], b[2]; 
a = b; 

powód, dla którego można nie dlatego zarówno a i b we fragmencie kodu powyżej zaniku do rvalues ​​typu wskaźnikowego zgodnie ze zwykłymi regułami C++ dla rozpadu tablica-wskaźnik opisanego w 4.2 [conv.array]. Oczywiście, wartość rurn, jeśli nie jest dozwolona po lewej stronie nieprzeciążonego operator=.

-1

Tablice nie są pierwszą klasą w C++; nie możesz przekazać ich jako argumentów dla funkcji, na przykład (rozpadają się na wskaźniki, chociaż możesz przekazywać wskaźniki i odniesienia do tablic do). Ponadto nie mają semantyki wartości.