Gibt es eine elegante Möglichkeit, ein const std::vector<const T>
Like const T a[] = { ... }
für eine feste (und kleine) Anzahl von Werten zu erstellen und zu initialisieren ?
Ich muss häufig eine Funktion aufrufen, die a erwartet vector<T>
, aber diese Werte werden sich in meinem Fall nie ändern.
Im Prinzip dachte ich an so etwas
namespace {
const std::vector<const T> v(??);
}
da v außerhalb dieser Kompilierungseinheit nicht verwendet wird.
Wenn Sie fragen, wie ein const-Vektor so initialisiert werden soll, dass er interessante Inhalte enthält, besteht die Antwort wahrscheinlich darin, den Kopierkonstruktor zu verwenden. Zuerst füllen Sie mühsam einen Vektor aus, dann erstellen Sie daraus Ihren neuen const-Vektor. Oder Sie können die
vector<InputIterator>(InputIterator, InputIterator)
Konstruktorvorlage verwenden, um aus einem anderen Container oder Array zu initialisieren. Wenn es sich um ein Array handelt, könnte dies mit einer Initialisierungsliste definiert worden sein.So etwas ist hoffentlich nah an dem, was Sie wollen:
const T ra[3] = {t1, t2, t3}; const vector<const T> v(ra, ra+3);
Wenn Sie fragen, wie ein konstanter Vektor an eine Funktion übergeben werden soll, die einen Vektor akzeptiert, lautet die Antwort entweder:
oder
const_cast
diese Option, um die Konstanz zu entfernen und sie an eine Funktion zu übergeben, die einen Nicht-Konstanten-Vektor verwendet, von der Sie jedoch zufällig wissen, dass sie den Vektor nicht ändert.Letzteres ist eines der Dinge, die zu Recht dazu führen, dass jeder, der es sieht, Kommentare zu Schutzbrillen abgibt und dass sie nichts tun. Es ist genau das, wofür es
const_cast
ist, aber es gibt ein ziemlich starkes Argument, das besagt, dassconst_cast
Sie bereits verloren haben , wenn Sie es brauchen .Beides zu tun (mit dem Kopierkonstruktor einen konstanten Vektor aus einem nicht konstanten Vektor zu erstellen und dann die Konstanz wegzuwerfen) ist definitiv falsch - Sie sollten nur einen nicht konstanten Vektor verwenden. Wählen Sie also höchstens eines davon aus, um es zu tun ...
[ Bearbeiten: habe gerade bemerkt, dass Sie über einen Unterschied zwischen
vector<T>
und sprechenconst vector<const T>
. Leider in der STL,vector<const T>
undvector<T>
sind völlig unabhängige Typen, und die einzige Möglichkeit, zwischen ihnen zu konvertieren, ist durch Kopieren. Dies ist ein Unterschied zwischen Vektoren und Arrays - aT**
kann lautlos und sicher inconst T *const *
] konvertiert werdenquelle
Kurzer und schmutziger Weg (ähnlich wie bei 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")); }
Jetzt verfügt C ++ 11 über Initialisierungslisten, sodass Sie dies nicht auf diese Weise tun oder sogar Boost verwenden müssen. Als Beispiel können Sie Folgendes in C ++ 11 effizienter ausführen:
#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; } }
Es ist jedoch immer noch nicht so effizient wie die Verwendung einer C ++ 11-Initialisierungsliste, da kein
operator=(vlist_of&&)
Vektor definiert ist.Die Art und Weise, wie tjohns20 wie folgt modifiziert wurde, könnte ein besseres c ++ 11 sein
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; } }
quelle
Wie andere bereits gesagt haben, können Sie einen Vektor nicht auf die gleiche Weise wie ein Array im C-Stil initiieren, es sei denn, Sie geben ihm Zeiger auf ein Quellarray. Wenn Ihr Vektor in diesem Fall eine globale Konstante ist, verwenden Sie stattdessen einfach ein altes Array im C-Stil.
const int MyInts[] = { 1, 2, 3, 4, 5}; const size_t NumMyInts = sizeof(MyInts)/sizeof(MyInts[0]);
Sie können sogar STL-Algorithmen für dieses Array verwenden, genauso wie Sie Algorithmen für einen konstanten Vektor verwenden würden ...
const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);
quelle
Sie können dies in zwei Schritten tun:
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]))); }
Vielleicht nicht so schön wie Sie möchten, aber funktional.
quelle
Wie wäre es mit:
int ar[]={1,2,3,4,5,6}; const int TotalItems = sizeof(ar)/sizeof(ar[0]); std::vector<int> v(ar, ar+TotalItems);
quelle
Alte Frage, aber ich bin heute auf dasselbe Problem gestoßen. Hier ist der Ansatz, der für meine Zwecke am akzeptabelsten war:
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; }
Beispiel zur Vermeidung übermäßigen Kopierens:
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; }
quelle
Wenn sie alle gleich sind, können Sie es einfach tun
vector<T> vec(num_items, item);
aber ich nehme an, dass dies nicht der Fall ist - in diesem Fall ist der wahrscheinlich ordentlichste Weg:
vector<T> vec(num_items); vec[0] = 15; vec[1] = 5; ...
Mit C ++ 0x können Sie eine Initialisierungsliste genau so verwenden, wie Sie es sich vorstellen, aber das ist momentan leider nicht sehr gut.
quelle
Basierend auf der Antwort von Shadow2531 verwende ich diese Klasse, um Vektoren zu initialisieren, ohne tatsächlich von std :: vector zu erben, wie es die Lösung von Shadow getan hat
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; };
Verwendung:
std::vector<int> testVec = vector_init<int>(1)(2)(3)(4)(5).end();
Im Vergleich zu Steve Jessops Lösung wird viel mehr Code erstellt, aber wenn die Array-Erstellung nicht leistungskritisch ist, finde ich es eine gute Möglichkeit, ein Array in einer einzelnen Zeile zu initialisieren
quelle
Ich bin mir nicht sicher, ob ich dich richtig verstanden habe. Ich verstehe Ihre Frage so: Sie möchten einen Vektor mit einer großen Anzahl von Elementen initialisieren. Was ist falsch an der Verwendung
push_back()
des Vektors? :-)Wenn Sie die Anzahl der zu speichernden Elemente kennen (oder sicher sind, dass weniger als die nächste Potenz von 2 gespeichert wird), können Sie dies tun, wenn Sie einen Vektor von Zeigern vom Typ X haben (funktioniert nur mit Zeigern):
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];
Achten Sie darauf, dass Sie nicht mehr als die nächste Potenz von 2 Elementen hinzufügen, auch wenn Sie diese verwenden
push_back()
. Zeiger aufv.begin()
sind dann ungültig.quelle