2015-02-20 12 views
8

Mam czarną skrzynkę C++ funkcja, która nie ma dostępu do jego kodu źródłowego:Odniesienie do częściowego segmentu wektora?

void blackbox(vector<int> &input); 

Ta funkcja modyfikuje element wektora wejściowego w nieznanym sposób.

Problem jaki mam teraz polega na tym, że chcę zastosować funkcję czarnej skrzynki tylko dla częściowego segmentu wektora, na przykład ostatnich 500 elementów wektora. Tak, to jest rutynowe, które napisałem, aby osiągnąć ten cel:

vector<int> foo (5,1000); 
vector<int> bar (foo.end()-500,foo.end()); 

blackbox(bar); 

swap_ranges(foo.end()-500,foo.end(),bar.begin()); 

Ten kod może działać, ale czy istnieje lepszy sposób to zrobić?

Byłoby dobrze, gdybym mógł zdefiniować odniesienie wektorowe tylko dla segmentu istniejącego wektora zamiast tworzyć kopię. Nie jest mi tak dobrze z kopiowaniem i zamianą części w powyższy kod; ponieważ ta procedura jest tak często wywoływana, to myślę, że wielokrotne kopiowanie i zamiana spowalnia kod. Gdybym znał dokładną operację wykonywaną przez blok, przepisałbym tę funkcję tak, aby pobierała iteratory wektorowe jako argumenty wejściowe . Niestety nie jest to obecnie możliwe.

+4

Ten przykład ilustruje, jak miło jest być w stanie przejść do funkcji iteratory zamiast pojemników. –

+0

Nawet jeśli dysponowałeś kodem źródłowym, może nie być możliwe przepisanie tej funkcji w celu pobrania iteratorów jako jedynych argumentów (np. Jeśli wykona wstawienia). – Beta

Odpowiedz

2

Nie ma dobrze zdefiniowanego sposobu osiągnięcia tej funkcji. Z ogromnymi zastrzeżeniami i ostrzeżeniami, może on (przynajmniej dla jednej wersji GCC) zostać zhakowany, jak poniżej, lub możesz napisać coś o lepiej zdefiniowanym zachowaniu, ale na podstawie aktualnej implementacji Twojego kompilatora std::vector ....

.. zhackowany. To nie zadziała, jeśli zostanie wykonana jakakolwiek inna operacja wpływająca na wektor ogólny. Może nie być przenośny/kontynuować pracę/pracę z wszystkimi poziomami optymalizacji/pracować we wtorki/używać na własne ryzyko itp. To zależy od pustej optymalizacji klasy bazowej.

Trzeba niestandardową przydzielania ale jest pewien haczyk: podzielnik nie może mieć dowolny stan lub będzie to zmienić binarnego układu obiektu vector, więc skończyć z tym:

#include <iostream> 
#include <vector> 

template <typename Container> // easy to get this working... 
void f(Container& v) 
{ 
    std::cout << "f() v.data() " << v.data() << ", v.size() " << v.size() << '\n'; 
    for (int& n : v) n += 10; 
} 

void g(std::vector<int>& v) // hard to get this working... 
{ 
    std::cout << "g() v.data() " << v.data() << ", v.size() " << v.size() << '\n'; 
    for (int& n : v) n += 100; 
} 

int* p_; // ouch: can't be a member without changing vector<> memory layout 


struct My_alloc : std::allocator<int> 
{ 
    // all no-ops except allocate() which returns the constructor argument... 

    My_alloc(int* p) { p_ = p; } 

    template <class U, class... Args> 
    void construct(U* p, Args&&... args) { std::cout << "My_alloc::construct(U* " << p << ")\n"; } 

    template <class U> void destroy(U* p) { std::cout << "My_alloc::destroy(U* " << p << ")\n"; } 

    pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0) 
    { 
     std::cout << "My_alloc::allocate() return " << p_ << "\n"; 
     return p_; 
    } 
    void deallocate(pointer p, size_type n) { std::cout << "deallocate\n"; } 

    template <typename U> 
    struct rebind { typedef My_alloc other; }; 
}; 

int main() 
{ 
    std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
    std::cout << "main() v.data() " << v.data() << '\n'; 
    My_alloc my_alloc(&v[3]); // first element to "take over" 
    std::vector<int, My_alloc> w(3, my_alloc); // num elements to "take over" 
    f(w); 
    g(reinterpret_cast<std::vector<int>&>(w)); 
    for (int n : v) std::cout << n << ' '; 
    std::cout << '\n'; 
    std::cout << "sizeof v " << sizeof v << ", sizeof w " << sizeof w << '\n'; 
} 

Output :

main() v.data() 0x9d76008 
My_alloc::allocate() return 0x9d76014 
My_alloc::construct(U* 0x9d76014) 
My_alloc::construct(U* 0x9d76018) 
My_alloc::construct(U* 0x9d7601c) 
f() v.data() 0x9d76014, v.size() 3 
g() v.data() 0x9d76014, v.size() 3 
0 1 2 113 114 115 6 7 8 9 
sizeof v 12, sizeof w 12 
My_alloc::destroy(U* 0x9d76014) 
My_alloc::destroy(U* 0x9d76018) 
My_alloc::destroy(U* 0x9d7601c) 
deallocate 

Zobacz uruchomić here

Powiązane problemy