Czy jest eleganckim sposobem tworzenia i zainicjować const std::vector<const T>
podobny const T a[] = { ... }
do stałej (i małych) liczba wartości?
Muszę często wywoływać funkcję, która oczekuje a vector<T>
, ale te wartości nigdy się nie zmienią w moim przypadku.
W zasadzie pomyślałem o czymś takim
namespace {
const std::vector<const T> v(??);
}
ponieważ v nie będzie używane poza tą jednostką kompilacji.
Jeśli pytasz, jak zainicjować wektor const, aby miał interesującą zawartość, to prawdopodobnie odpowiedzią jest użycie konstruktora kopiującego. Najpierw mozolnie wypełniasz wektor, a następnie tworzysz z niego nowy wektor const. Lub możesz użyć
vector<InputIterator>(InputIterator, InputIterator)
szablonu konstruktora do zainicjowania z innego rodzaju kontenera lub tablicy. Jeśli tablica, to można ją zdefiniować za pomocą listy inicjalizacyjnej.Mam nadzieję, że coś takiego jest bliskie temu, czego chcesz:
const T ra[3] = {t1, t2, t3}; const vector<const T> v(ra, ra+3);
Jeśli pytasz, jak przekazać wektor const do funkcji, która przyjmuje wektor, odpowiedź brzmi:
lub
const_cast
do usunięcia stałej, aby przekazać ją do funkcji, która pobiera wektor inny niż stała, ale o której wiesz, że nie zmodyfikuje wektora.Ta ostatnia jest jedną z tych rzeczy, które całkiem słusznie sprawią, że każdy, kto to zobaczy, będzie komentował gogle i fakt, że nic nie robią. Właśnie po to
const_cast
jest, ale istnieje dość silny argument, który mówi, że jeśli potrzebujeszconst_cast
, już przegrałeś.Robienie obu tych rzeczy (tworzenie wektora const z innego niż const za pomocą konstruktora kopiującego, a następnie odrzucanie stałej) jest zdecydowanie złe - powinieneś był po prostu użyć wektora innego niż const. Więc wybierz co najwyżej jedno z nich do zrobienia ...
[ Edycja: właśnie zauważyłem, że mówisz o różnicy między
vector<T>
iconst vector<const T>
. Niestety w STLvector<const T>
ivector<T>
są całkowicie niepowiązane typy, a jedynym sposobem na konwersję między nimi jest kopiowanie. To jest różnica między wektorami a tablicami - aT**
można dyskretnie i bezpiecznie przekonwertować naconst T *const *
]źródło
Krótki i brudny sposób (podobny do Boost
list_of()
)#include <iostream> #include <vector> #include <iterator> #include <algorithm> using namespace std; template <typename T> struct vlist_of : public vector<T> { vlist_of(const T& t) { (*this)(t); } vlist_of& operator()(const T& t) { this->push_back(t); return *this; } }; int main() { const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5); copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\n")); }
Teraz C ++ 11 ma listy inicjatorów, więc nie musisz tego robić w ten sposób ani nawet używać Boost. Ale, jako przykład, możesz wykonać powyższe czynności w C ++ 11 wydajniej w ten sposób:
#include <iostream> #include <vector> #include <utility> #include <ostream> using namespace std; template <typename T> struct vlist_of : public vector<T> { vlist_of(T&& t) { (*this)(move(t)); } vlist_of& operator()(T&& t) { this->push_back(move(t)); return *this; } }; int main() { const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5); for (const auto& i: v) { cout << i << endl; } }
Ale nadal nie jest tak wydajne, jak używanie listy inicjalizującej C ++ 11, ponieważ nie ma
operator=(vlist_of&&)
zdefiniowanej dla wektora.Sposób tjohns20 zmodyfikowany jak poniżej może być lepszym C ++ 11
vlist_of
:#include <iostream> #include <vector> #include <utility> using namespace std; template <typename T> class vlist_of { public: vlist_of(T&& r) { (*this)(move(r)); } vlist_of& operator()(T&& r) { v.push_back(move(r)); return *this; } vector<T>&& operator()() { return move(v); } private: vector<T> v; }; int main() { const auto v = vlist_of<int>(1)(2)(3)(4)(5)(); for (const auto& i : v) { cout << i << endl; } }
źródło
Jak powiedzieli inni, nie możesz zainicjować wektora w ten sam sposób, w jaki możesz zainicjować tablicę w stylu C, chyba że podasz mu wskaźniki do tablicy źródłowej. Ale w takim przypadku, jeśli twój wektor jest globalną stałą, dlaczego nie użyć zamiast tego starej tablicy w stylu C.
const int MyInts[] = { 1, 2, 3, 4, 5}; const size_t NumMyInts = sizeof(MyInts)/sizeof(MyInts[0]);
Możesz nawet użyć algorytmów STL przeciwko tej tablicy, w taki sam sposób, w jaki używałbyś algorytmów do wektora const ...
const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);
źródło
Możesz to zrobić w dwóch krokach:
namespace { const T s_actual_array[] = { ... }; const std::vector<const T> s_blah(s_actual_array, s_actual_array + (sizeof(s_actual_array) / sizeof(s_actual_array[0]))); }
Może nie tak piękne, jak byś chciał, ale funkcjonalne.
źródło
Co powiesz na:
int ar[]={1,2,3,4,5,6}; const int TotalItems = sizeof(ar)/sizeof(ar[0]); std::vector<int> v(ar, ar+TotalItems);
źródło
Stare pytanie, ale spotkałem się dzisiaj z tym samym problemem, oto podejście, które było najbardziej akceptowalne dla moich celów:
vector<int> initVector(void) { vector<int> initializer; initializer.push_back(10); initializer.push_back(13); initializer.push_back(3); return intializer; } int main() { const vector<int> a = initVector(); return 0; }
Przykład unikania nadmiernego kopiowania:
vector<int> & initVector(void) { static vector<int> initializer; if(initializer.empty()) { initializer.push_back(10); initializer.push_back(13); initializer.push_back(3); } return intializer; } int main() { const vector<int> & a = initVector(); return 0; }
źródło
Jeśli wszystkie są takie same, możesz po prostu zrobić
vector<T> vec(num_items, item);
ale zakładam, że tak nie jest - w takim przypadku najładniejszy sposób to prawdopodobnie:
vector<T> vec(num_items); vec[0] = 15; vec[1] = 5; ...
C ++ 0x pozwoli ci użyć listy inicjalizatorów dokładnie tak, jak myślisz, ale niestety nie jest to zbyt dobre w tej chwili.
źródło
Na podstawie odpowiedzi Shadow2531 używam tej klasy do inicjalizacji wektorów, bez dziedziczenia po std :: vector, tak jak to zrobiło rozwiązanie Shadow
template <typename T> class vector_init { public: vector_init(const T& val) { vec.push_back(val); } inline vector_init& operator()(T val) { vec.push_back(val); return *this; } inline std::vector<T> end() { return vec; } private: std::vector<T> vec; };
Stosowanie:
std::vector<int> testVec = vector_init<int>(1)(2)(3)(4)(5).end();
W porównaniu z rozwiązaniem Steve'a Jessopa tworzy o wiele więcej kodu, ale jeśli tworzenie tablicy nie jest krytyczne dla wydajności, uważam, że jest to dobry sposób na zainicjowanie tablicy w jednej linii
źródło
Nie jestem pewien, czy dobrze cię zrozumiałem. Rozumiem twoje pytanie w ten sposób: chcesz zainicjować wektor dla dużej liczby elementów. Co jest złego w używaniu
push_back()
na wektorze? :-)Jeśli znasz liczbę elementów do przechowywania (lub jesteś pewien, że będzie przechowywać mniej niż następna potęga 2), możesz to zrobić, jeśli masz wektor wskaźników typu X (działa tylko ze wskaźnikami):
std::vector< X* > v; v.reserve(num_elems); X* p = v.begin(); for (int count = 0; count < num_elems; count++) p[count] = some_source[count];
Uważaj na dodanie więcej niż następnej mocy 2 elementów, nawet jeśli używasz
push_back()
. Wskaźniki dov.begin()
będą wtedy nieważne.źródło