jak zainicjalizować 'const std::vector' jak tablicę c

Czy istnieje elegancki sposób na utworzenie i zainicjalizowanie const std::vector<const T> Jak const T a[] = { ... } do stałej (i małej) liczby wartości?
Muszę często wywoływać funkcję, która oczekuje vector<T>, ale te wartości nigdy się nie zmienią w moim przypadku.

W zasadzie myślałem o czymś w rodzaju

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

Ponieważ v nie będzie używany poza tą jednostką kompilacji.

 79
Author: vscharf, 2008-10-23

10 answers

Albo trzeba poczekać na C++0x albo użyć czegoś w rodzaju Boost.Przypisać , Aby to zrobić.

Np.:

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

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

Dla C++11:

vector<int> luggage_combo = { 1, 2, 3, 4, 5 };
 61
Author: Ferruccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 00:43:14

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. Możesz też użyć szablonu konstruktora vector<InputIterator>(InputIterator, InputIterator) do inicjalizacji z innego rodzaju kontenera lub tablicy. Jeśli tablica, to mogła być zdefiniowana za pomocą listy inicjalizacyjnej.

Coś takiego jest, mam nadzieję, blisko tego, co Ty 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, to odpowiedź brzmi:

  • nie możesz, ponieważ funkcja może zmienić wektor i twój obiekt / odniesienie jest const. Zrób niezakończoną kopię oryginału i przekaż ją.

Lub

  • użyj const_cast, aby usunąć konsternację, aby przekazać ją do funkcji, która przyjmuje wektor nie-const, ale która tak się składa, że wiesz, że nie zmodyfikuje wektor.
[11]}ta ostatnia jest jedną z tych rzeczy, które, całkiem słusznie, sprawią, że każdy, kto ją zobaczy, będzie komentował gogle i fakt, że nic nie robią. Dokładnie po to jest const_cast, ale istnieje dość silny argument, który mówi, że jeśli potrzebujesz const_cast, już przegrałeś.

Robienie obu tych rzeczy (tworzenie wektora const z nie-const z konstruktorem kopiującym, a następnie odrzucanie konstruowania) jest zdecydowanie złe - powinieneś był po prostu użyć wektor niezerowy. Więc wybierz co najwyżej jeden z nich do zrobienia...

[Edit: właśnie zauważyłem, że mówisz o różnicy między vector<T> a const vector<const T>. Niestety w STL, vector<const T> i vector<T> są całkowicie niepowiązanymi typami, a jedynym sposobem na konwersję między nimi jest kopiowanie. Jest to różnica między wektorami a tablicami-a T** można spokojnie i bezpiecznie przekształcić na const T *const *]

 39
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-07 13:37:15

Short and dirty way (podobnie jak 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"));
}

Teraz C++11 ma listy inicjalizacyjne, więc nie musisz tego robić w ten sposób ani nawet używać Boost. Ale, jako przykład, można zrobić powyższe w C++11 bardziej efektywnie, jak to:

    #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 wydajny jak użycie listy inicjalizacyjnej C++11, ponieważ nie ma operator=(vlist_of&&) zdefiniowanej dla wektora.

Tjohns20 ' s way modified like the following might be a better 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;
    }
    
}
 15
Author: Shadow2531,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-07 13:34:22

Jak powiedzieli inni, nie możesz inicjować wektora w taki sam sposób jak możesz inicjować tablicę w stylu C, chyba że podasz jej wskaźniki do tablicy źródłowej. Ale w takim przypadku, jeśli twój wektor jest globalnym const, dlaczego nie użyć starej tablicy w stylu C?

const int MyInts[] = {
1, 2, 3, 4, 5};

const size_t NumMyInts = sizeof(MyInts)/sizeof(MyInts[0]);

Można nawet użyć algorytmów STL przeciwko tej tablicy, tak samo jak algorytmy przeciwko wektorowi const...

const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);
 12
Author: John Dibling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 21:06:45

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.
 6
Author: janm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 21:25:21

A może:

int ar[]={1,2,3,4,5,6};
const int TotalItems = sizeof(ar)/sizeof(ar[0]);
std::vector<int> v(ar, ar+TotalItems);
 5
Author: opal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-25 11:22:35

Stare pytanie, ale natknąłem się dziś na ten sam problem, 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;
}
 3
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-14 22:05:28

Jeśli wszystkie są takie same możesz po prostu zrobić

vector<T> vec(num_items, item);

Ale zakładam, że nie są - w takim wypadku najprościej będzie:

vector<T> vec(num_items);
vec[0] = 15;
vec[1] = 5;
...

C++0x pozwoli Ci używać listy inicjalizatorów dokładnie tak, jak myślisz, ale to niestety, nie za wiele dobrego.

 0
Author: Peter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 21:35:50

Bazując na odpowiedzi Shadow2531, używam tej klasy do inicjalizacji wektorów, bez dziedziczenia z std:: vector, tak jak rozwiązanie Shadowa

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

Użycie:

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

W porównaniu do rozwiązania Steve ' a Jessopa tworzy znacznie więcej kodu, ale jeśli tworzenie tablicy nie jest kluczowe dla wydajności, uważam, że jest to dobry sposób na zainicjowanie tablicy w jednej linii

 0
Author: tjohns20,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-09 16:45:13

Nie wiem, czy dobrze Cię zrozumiałem. Rozumiem twoje pytanie w ten sposób: chcesz zainicjalizować wektor do dużej liczby elementów. Co jest złego w używaniu push_back() na wektorze? :-)

Jeśli znasz liczbę elementów do zapisania (lub jesteś pewien, że przechowuje mniej niż następna moc 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 dodawanie więcej niż następnej mocy 2 elementów, nawet jeśli używasz push_back(). Wskaźniki do v.begin() będą wtedy niepoprawne.

 0
Author: mstrobl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-07 13:37:58