2015-02-20 15 views
8

Ho una scatola nera C++ funzione che non ho accesso al suo codice sorgente:Riferimento a un segmento parziale di un vettore?

void blackbox(vector<int> &input); 

Questa funzione modifica l'elemento del vettore di ingresso in maniera sconosciuta.

Il problema che ho ora è che voglio applicare la funzione black box solo per un segmento parziale di un vettore, ad esempio, gli ultimi 500 elementi di un vettore. Quindi, questa è la routine che ho scritto per raggiungere questo obiettivo:

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

blackbox(bar); 

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

Questo codice può funzionare, ma c'è un modo migliore per fare questo?

Sarebbe bello se io possa definire un riferimento vettoriale solo per un segmento di un vettore esistente, invece di creare una copia. Non mi sento molto a mio agio con la copia e lo scambio di parti nel codice sopra; dal momento che questa routine è invocata di frequente da , penso che la copia e lo scambio ripetuti rallentino il codice. Se conoscessi le esatte operazioni eseguite dalla casella di blocco, vorrei riscrivere la funzione in modo che utilizzi gli iteratori vettoriali come argomenti di input . Sfortunatamente, questo non è possibile al momento.

+4

Questo esempio illustra come è bello essere in grado di passare a funzioni iteratori invece di contenitori. –

+0

Anche se si avesse il codice sorgente, potrebbe non essere possibile riscrivere la funzione per prendere gli iteratori come unici argomenti (ad esempio se esegue inserimenti). – Beta

risposta

2

Non esiste un modo ben definito per ottenere questa funzionalità. Con enormi avvertimenti e avvertenze, è possibile (per una versione GCC almeno) essere hackerato come di seguito, o si potrebbe scrivere qualcosa con un comportamento migliore ma basato sull'implementazione attuale del tuo compilatore std::vector ....

Quindi .. . violato. Ciò non funzionerà se insert/erase/resize/reserve/clear/push_back o qualsiasi altra operazione che interessa il vettore generale viene eseguita. Potrebbe non essere portabile/continuare a lavorare/lavorare con tutti i livelli di ottimizzazione/lavorare di martedì/usare a proprio rischio, ecc. Dipende dall'ottimizzazione della classe base vuota.

è necessario un allocatore personalizzato, ma c'è un problema: l'allocatore non può avere qualsiasi stato o che sarà modificare il layout binario dell'oggetto vector, così abbiamo finire con questo:

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

uscita :

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 

Vedi correre here

Problemi correlati