it-swarm.com.de

wie man 'const std :: vector <T>' wie ein c-Array initialisiert

Gibt es eine elegante Möglichkeit, einen const std::vector<const T> wie const T a[] = { ... } auf eine feste (und kleine) Anzahl von Werten zu erstellen und zu initialisieren?
Ich muss häufig eine Funktion aufrufen, die einen vector<T> erwartet, aber diese Werte werden sich in meinem Fall niemals ändern.

Im Prinzip habe ich an so etwas gedacht

namespace {
  const std::vector<const T> v(??);
}

da v nicht außerhalb dieser Kompilierungseinheit verwendet wird.

78
vscharf

Dazu müssen Sie entweder auf C++ 0x warten oder etwas wie Boost.Assign verwenden.

z.B.:

#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope

vector<int> v;
v += 1,2,3,4,5;

für C++ 11:

vector<int> luggage_combo = { 1, 2, 3, 4, 5 };
60
Ferruccio

Wenn Sie sich fragen, wie Sie einen const-Vektor mit interessanten Inhalten initialisieren können, lautet die Antwort wahrscheinlich der Kopierkonstruktor. Zuerst füllen Sie mühsam einen Vektor aus, und erstellen dann daraus einen neuen Vektor. Oder Sie können die Konstruktorvorlage Vektor <InputIterator> (InputIterator, InputIterator) verwenden, um eine andere Art von Container oder Array zu initialisieren. Wenn ein Array, dann könnte dies mit einer Initialisierungsliste definiert worden sein.

So etwas ist hoffentlich nahe an dem, was Sie wollen:

const T ra[3] = {t1, t2, t3};
const vector<const T> v(ra, ra+3);

Wenn Sie fragen, wie Sie einen const-Vektor an eine Funktion übergeben, die einen Vektor übernimmt, dann lautet die Antwort entweder:

  • das ist nicht möglich, da die Funktion den Vektor ändern kann und Ihr Objekt/Bezug konstant ist. Erstellen Sie eine Kopie des Originals, und übergeben Sie diese in.

oder

  • verwenden Sie const_cast, um die Konstante zu entfernen, um sie an eine Funktion zu übergeben, die einen Nicht-Konstanten-Vektor verwendet, von dem Sie jedoch wissen, dass er den Vektor nicht ändert.

Letzteres ist eines dieser Dinge, das zu Recht jeden, der es sieht, dazu bringt, Kommentare zu Brillen zu machen und die Tatsache, dass sie nichts tun. Genau das ist const_cast, aber es gibt ein ziemlich starkes Argument, das besagt, wenn Sie const_cast brauchen, haben Sie bereits verloren.

Beides zu tun (Erstellen eines Konstantenvektors aus einem Nichtkonstanten mit dem Kopierkonstruktor und anschließendes Wegwerfen der Konstante) ist definitiv falsch - Sie sollten nur einen Nichtkonstantenvektor verwendet haben. Wählen Sie also höchstens eine davon aus ...

[Bearbeiten: Ich habe gerade bemerkt, dass Sie über einen Unterschied zwischen Vektor <T> und const Vektor <const T> sprechen. In der STL sind der Vektor <const T> und der Vektor <T> völlig unabhängige Typen, und die einzige Möglichkeit zum Konvertieren zwischen ihnen ist das Kopieren. Dies ist ein Unterschied zwischen Vektoren und Arrays - ein T ** kann geräuschlos und sicher in const T * const * konvertiert werden.]

39
Steve Jessop

Kurz und schmutzig (ähnlich Boost's 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"));
}

In C++ 11 gibt es nun Initializer-Listen. Sie müssen also nicht so vorgehen oder Boost verwenden. Als ein Beispiel können Sie das in C++ 11 auf folgende Weise 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 für vector kein Operator = (vlist_of &&) definiert ist.

tjohns20's modifizierte Art und Weise könnte wie folgt eine bessere c ++ 11 vlist_of sein:

#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;
    }

}
15
Shadow2531

Wie andere bereits gesagt haben, können Sie einen Vektor nicht auf dieselbe Weise wie Sie ein Array im C-Stil initiieren, es sei denn, Sie geben ihm einen Zeiger auf ein Quellarray. Wenn Ihr Vektor jedoch ein globaler const ist, warum verwenden Sie nicht 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 const-Vektor verwenden würden.

const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);
12
John Dibling

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.

6
janm

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);
5
opal

Alte Frage, aber ich bin heute auf dieselbe Frage 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, um übermäßiges Kopieren zu vermeiden:

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;
}
3
Kevin

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 los mit Push_back () für den Vektor? :-)

Wenn Sie die Anzahl der zu speichernden Elemente kennen (oder sicher sind, dass weniger als die nächste Potenz von 2 gespeichert werden), 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, mehr als die nächste Potenz von 2 Elementen hinzuzufügen, auch wenn Sie Push_back () verwenden. Zeiger auf v.begin () sind dann ungültig.

0
mstrobl

Wenn sie alle gleich sind, können Sie es einfach tun

vector<T> vec(num_items, item);

aber ich gehe davon aus, dass dies nicht der Fall ist. In diesem Fall ist der wahrscheinlichste Weg wahrscheinlich:

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 denken, aber das ist Derzeit leider nicht sehr gut.

0
Peter

Basierend auf der Antwort von Shadow2531 verwende ich diese Klasse zum Initialisieren von Vektoren, ohne tatsächlich von std :: vector zu erben, wie es die Lösung von Shadow tat

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;
};

Verwendungszweck:

std::vector<int> testVec = vector_init<int>(1)(2)(3)(4)(5).end();

Verglichen mit der Lösung von Steve Jessop wird viel mehr Code erstellt, aber wenn die Array-Erstellung nicht leistungskritisch ist, finde ich es eine gute Möglichkeit, ein Array in einer Zeile zu initialisieren

0
tjohns20