Jak skopiować zawartość tablicy do std:: vector w C++ bez zapętlania?

Mam tablicę wartości, która jest przekazywana do mojej funkcji z innej części programu, którą muszę zapisać do późniejszego przetworzenia. Ponieważ Nie wiem, ile razy moja funkcja zostanie wywołana, zanim nadejdzie czas przetwarzania danych, potrzebuję dynamicznej struktury pamięci masowej, więc wybrałem std::vector. Nie chcę wykonywać standardowej pętli do push_back wszystkich wartości indywidualnie, byłoby miło, gdybym mógł skopiować to wszystko używając czegoś podobnego do memcpy.

Author: phoenix, 2008-11-03

10 answers

Jeśli możesz skonstruować wektor po uzyskaniu tablicy i rozmiaru tablicy, możesz po prostu powiedzieć:

std::vector<ValueType> vec(a, a + n);

...zakładając, że a jest twoją tablicą, a n jest liczbą elementów, które zawiera. W przeciwnym razie, std::copy() w / resize() załatwi sprawę.

Trzymałbym się z dala od memcpy(), chyba że możesz być pewien, że wartości są zwykłymi typami danych (POD).

Warto również zauważyć, że żadna z nich nie unika pętli for-tylko pytanie, czy musisz ją zobaczyć w swoim kodzie albo i nie. O (n) wydajność runtime jest nieunikniona przy kopiowaniu wartości.

Na koniec zauważ, że tablice w stylu C są doskonale poprawnymi kontenerami dla większości algorytmów STL-wskaźnik raw jest równoważny begin(), a (ptr + n) jest równoważny end().

 86
Author: Drew Hall,
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
2017-03-10 14:54:50

Było tu wiele odpowiedzi i prawie wszystkie z nich wykonają zadanie.

Jest jednak jakaś myląca Rada!

Oto opcje:

vector<int> dataVec;

int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

// Method 1: Copy the array to the vector using back_inserter.
{
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
    dataVec.reserve(dataVec.size() + dataArraySize);
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 3: Memcpy
{
    dataVec.resize(dataVec.size() + dataArraySize);
    memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}

// Method 4: vector::insert
{
    dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}

// Method 5: vector + vector
{
    vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
    dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}

Aby wyciąć długą historię, metoda 4, używając vector:: insert, jest najlepsza dla scenariusza bsruth.

Oto kilka krwawych szczegółów:

Metoda 1 jest prawdopodobnie najłatwiejsza do zrozumienia. Wystarczy skopiować każdy element z tablicy i wcisnąć go z tyłu wektora. Niestety, powoli. Ponieważ istnieje pętla (implikowana z funkcją kopiowania), każdy element musi być traktowany indywidualnie; nie można poprawić wydajności w oparciu o fakt, że wiemy, że tablica i wektory są sąsiadującymi blokami.

Metoda 2 jest sugerowaną poprawą wydajności do metody 1; wystarczy wstępnie zarezerwować rozmiar tablicy przed jej dodaniem. Dla dużych tablic ten Może pomóc. Jednak najlepszą radą tutaj jest nigdy nie używać rezerwy, chyba że profilowanie sugeruje możesz być w stanie uzyskać poprawę (lub musisz upewnić się, że Iteratory nie zostaną unieważnione). Bjarne zgadza się . Nawiasem mówiąc, odkryłem, że metoda ta wykonywała najwolniej przez większość czasu, chociaż staram się wyczerpująco wyjaśnić, dlaczego była regularnie znacząco wolniejsza niż metoda 1...

Metoda 3 jest starym rozwiązaniem-rzuć trochę C w problem! Działa dobrze i szybko dla typów POD. W tym przypadku resize jest wymagane do wywołania, ponieważ memcpy działa poza granicami wektora i nie ma sposobu, aby powiedzieć wektorowi, że jego rozmiar się zmienił. Poza tym, że jest brzydkim rozwiązaniem (kopiowanie bajtów!) pamiętaj, że to może być używane tylko dla typów POD . Nigdy nie użyłbym tego rozwiązania.

metoda 4 jest najlepszym sposobem. Jego znaczenie jest jasne, jest (zazwyczaj) najszybsze i działa dla dowolnych obiektów. Nie ma minusów stosowania tej metody do tego podanie.

metoda 5 jest modyfikacją metody 4-skopiowanie tablicy do wektora, a następnie jej dołączenie. Dobra opcja-generalnie szybka i przejrzysta.

Wiesz wreszcie, że możesz używać wektorów zamiast tablic, prawda? Nawet jeśli funkcja oczekuje tablic w stylu c, można użyć wektorów:
vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");
Mam nadzieję, że to komuś pomoże!
 170
Author: MattyT,
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-11-04 11:42:17

Jeśli wszystko, co robisz, to zastępujesz istniejące dane, możesz to zrobić

std::vector<int> data; // evil global :)

void CopyData(int *newData, size_t count)
{
   data.assign(newData, newData + count);
}
 26
Author: Torlack,
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-11-03 17:39:26

Std:: copy jest tym, czego szukasz.

 11
Author: luke,
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-11-03 17:07:34

Ponieważ mogę edytować tylko własną odpowiedź, zrobię odpowiedź złożoną z innych odpowiedzi na moje pytanie. Dziękuję wszystkim, którzy odpowiedzieli.

Używając std:: copy, to nadal działa w tle, ale nie musisz wpisywać kodu.

int foo(int* data, int size)
{
   static std::vector<int> my_data; //normally a class variable
   std::copy(data, data + size, std::back_inserter(my_data));
   return 0;
}

Używając zwykłej memcpy . Jest to prawdopodobnie najlepiej używane dla podstawowych typów danych (tj. int), ale nie dla bardziej złożonych tablic struktur lub klas.

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
 4
Author: bsruth,
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-11-03 20:28:38

Unikaj memcpy, mówię. Nie ma powodu, aby zadzierać z operacjami wskaźnikowymi, chyba że naprawdę musisz. Ponadto będzie działać tylko dla typów POD (takich jak int), ale zawiedzie, jeśli masz do czynienia z typami, które wymagają budowy.

 2
Author: Assaf Lavie,
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-11-03 17:17:55
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source

unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

std::vector<int> myvector (dataArraySize );//target

std::copy ( myints, myints+dataArraySize , myvector.begin() );

//myvector now has 1,2,3,...10 :-)
 2
Author: Antonio Ramasco,
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
2017-03-01 15:01:28

Oprócz metod przedstawionych powyżej, musisz upewnić się, że używasz std:: Vector.reserve (), std:: Vector.resize (), lub skonstruować wektor do rozmiaru, aby upewnić się, że wektor ma wystarczającą ilość elementów do przechowywania danych. jeśli nie, zepsujesz pamięć. Dotyczy to std:: copy() lub memcpy ().

Jest to powód użycia wektora.push_back (), nie można pisać poza końcem wektora.

 1
Author: Thomas Jones-Low,
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-11-03 17:29:02

Kolejna odpowiedź, ponieważ osoba powiedziała "Nie wiem, ile razy moja funkcja będzie wywoływana", możesz użyć metody Vector insert w taki sposób, aby dołączyć tablice wartości do końca wektora:

vector<int> x;

void AddValues(int* values, size_t size)
{
   x.insert(x.end(), values, values+size);
}

Podoba mi się ten sposób, ponieważ implementacja wektora powinna być w stanie zoptymalizować pod kątem najlepszego sposobu wstawiania wartości na podstawie typu iteratora i samego typu. Trochę odpowiadasz na temat implementacji stl.

Jeśli chcesz zagwarantować najszybsza prędkość i wiesz, że Twój typ jest typu POD, to polecam metodę resize w odpowiedzi Thomasa:

vector<int> x;

void AddValues(int* values, size_t size)
{
   size_t old_size(x.size());
   x.resize(old_size + size, 0);
   memcpy(&x[old_size], values, size * sizeof(int));
}
 1
Author: Shane Powell,
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-11-03 18:56:15

Zakładając, że wiesz jak duży jest element w wektorze:

std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));

Http://www.cppreference.com/wiki/stl/vector/start

 0
Author: Thomas Jones-Low,
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-11-03 17:09:15