2013-07-14 17 views
15

chcę powielać zawartość nośnika i chcesz, żeby być dołączone na końcu oryginalnego wektora tj v[i]=v[i+n] for i=0,2,...,n-1Dobry sposób, aby dołączyć wektor do siebie

szukam dobry sposób, aby to zrobić, nie z pętlą. Widziałem std::vector::insert, ale wersja iteracyjna zabrania iteratora na *this (tzn. Zachowanie jest niezdefiniowane).

Próbowałem też std::copy następująco (ale to spowodowało winy segmentacji):

copy(xx.begin(), xx.end(), xx.end());

+0

możliwe duplikat [błędne wyniki podczas dołączania wektor do siebie używając kopii and back \ _inserter] (http://stackoverflow.com/questions/11511510/wrong-results-when-appending-vector-to-self-using-copy-and-back-inserter) –

+1

@BenVoigt, Aby być uczciwym, kiedy zadałem to pytanie, spróbowałem i chciałem wiedzieć, dlaczego to nie zadziałało. Właściwie nie potrzebowałem eleganckiego rozwiązania roboczego, więc w komentarzach są tylko wzmianki o nim. – chris

+1

Muszę się zastanowić, czy większość ludzi wdrożyłaby tę implementację za pierwszym razem, gdyby zakodowali ją pętlą. – MarkB

Odpowiedz

21

Wow. Tak wiele odpowiedzi, które są bliskie, żadne z odpowiednimi elementami. Potrzebujesz zarówno resize (lub reserve), jak i copy_n wraz z zapamiętywaniem oryginalnego rozmiaru.

auto old_count = xx.size(); 
xx.resize(2 * old_count); 
std::copy_n(xx.begin(), old_count, xx.begin() + old_count); 

lub

auto old_count = xx.size(); 
xx.reserve(2 * old_count); 
std::copy_n(xx.begin(), old_count, std::back_inserter(xx)); 

Podczas korzystania reserve, copy_n jest wymagane, ponieważ end() punktów iterator jeden element poza końcem ... co oznacza, że ​​również nie jest „przed punktem wstawiania” pierwszej wstawiania i staje się nieważny.


23.3.6.5 [vector.modifiers] obiecuje, że dla insert i push_back:

Uwagi: Powoduje realokacji jeśli nowy rozmiar jest większy niż stary pojemności. Jeśli nie nastąpi żadna realokacja, wszystkie iteratory i odwołania przed punktem wstawienia zachowują ważność. Jeśli zostanie zgłoszony wyjątek inny niż przez konstruktora kopiowania, przenieś konstruktora, operator przypisania lub przenieś operator przypisania T lub dowolną operację InputIterator, nie ma żadnych efektów. Jeżeli konstruktor ruchu nie generuje wyjątku T, który nie jest CopyDablaczem, skutki są nieokreślone.

3

zrobiłbym to tak:

#include <algorithm> 
#include <vector> 
#include <utility> 

int main(int argc, char* argv[]) 
{ 
    std::vector<int> v1 = { 1, 2, 3, 4, 5 }; 

    { 
     std::vector<int> v2(v1.begin(), v1.end()); 
     std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); 
     std::swap(v1, v2); 
    } 

    return 0; 
} 

EDIT: Dodałam nieco bardziej wydajną wersję.

#include <algorithm> 
#include <vector> 
#include <utility> 

int main(int argc, char* argv[]) 
{ 
    std::vector<int> v1 = { 1, 2, 3, 4, 5 }; 

    { 
     typedef std::move_iterator<decltype(v1)::iterator> VecMoveIter; 
     std::vector<int> v2(v1); 
     std::copy(VecMoveIter(v1.begin()), VecMoveIter(v1.end()), std::back_inserter(v2)); 
     v1 = std::move(v2); 
    } 

    return 0; 
} 
+0

Zapomniałeś o istnieniu konstruktora kopiowania i 'std :: vector :: insert' :) – chris

+0

Nie jest to zła myśl, ponieważ zawartość wektorowa prawdopodobnie zostanie skopiowana do nowej lokalizacji. Ale dodajesz dodatkową kopię. Spróbuj skonstruować nowy wektor z odpowiednią pojemnością z góry. –

+0

Warto również raz skopiować i przenieść istniejące elementy zamiast tworzyć dwie nowe kopie każdej z nich. –

0

Za dołączenie więcej niż jednego gniazda duplikatów.

int main() { 
     std::vector<int> V; 
     V.push_back(1); 
     V.push_back(2); 

     int oldSize = V.size(); 
     int newSize = oldSize; 
     int nDupSlot = 4; 

     V.resize(nDupSlot * oldSize); 
     for(int i=0; i<(nDupSlot-1); ++i) { 
      std::copy_n(V.begin(), oldSize, V.begin() + newSize);  
      newSize = newSize + oldSize; 
     } 

     for(int i =0; i<V.size(); ++i) { 
      std::cout<<V[i]; 
      } 

     return 0; 
    } 

wyjściowa:

12121212 
0

To może nie być najbardziej skutecznym sposobem, ale na pewno jest prosta:

std::vector<int> toAppend(xx); 
xx.insert(xx.end(), toAppend.begin(), toAppend.end(); 
Powiązane problemy