Link to a partial segment of a vector?

I have a C ++ black box function that I do not have access to its source code:

void blackbox(vector<int> &input); 

This function modifies the input vector element in an unknown way.

Now the problem is that I want to apply the black box function only for a partial segment of a vector, for example, the last 500 elements of a vector. So this is the routine I wrote to achieve this:

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

This code may work, but is there a better way to do this?

It would be nice if I could define a vector link only for a segment of an existing vector, instead of creating a copy. It’s not very convenient for me to copy and replace parts in the above code; since this procedure is called so often, I think re-copying and sharing slows down the code. If I knew the exact operations performed by a block block, I would rewrite the function so that vector iterators of arguments are accepted as input. Unfortunately, this is not possible at the moment.

+8
c ++ iterator reference vector
source share
1 answer

There is no clearly defined way to achieve this functionality. With huge caveats and warnings, it can (for at least one version of GCC) hack, as shown below, or you could write something with clearer behavior, but based on the current implementation of the std::vector compiler ....

So ... hacked. This will not work if insert / erase / resize / reserve / clear / push_back or any other operation affecting the common vector. This may not be portable / continue to work / work with all levels of optimization / work on Tuesdays / use at your own risk, etc. It depends on optimizing an empty base class.

You need a special allocator, but there is a catch: the allocator cannot have any state or it will change the binary layout of the vector object, so we will end with this:

 #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 

See how it works here

+2
source share

All Articles