Reference to a partial segment of a vector? - c++

I have a black box C++ function which I don't have access to its source code:
void blackbox(vector<int> &input);
This function modifies the element of the input vector in an unknown manner.
The problem I have now 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 that I wrote to attain this goal:
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 good if I can define a vector reference only for a segment of
an existing vector, instead of creating a copy.
I am not so comfortable with the copying and swapping parts in the above code; since this routine is
invoked so frequently, I think the repeated copying and swapping slows down the code.
If I knew the exact operations done by the block box, I would rewrite the function so that it takes vector iterators as the input
arguments. Unfortunately, this is not possible at the moment.

There's no well-defined way to achieve this functionality. With huge caveats and warnings, it can (for one GCC version at least) be hacked as below, or you could perhaps write something with better defined behaviour but based on your compiler's current std::vector implementation....
So... hacked. This will not work if insert/erase/resize/reserve/clear/push_back or any other operation affecting the overall vector is performed. It may not be portable / continue working / work with all optimisation levels / work on Tuesdays / use at own risk etc.. It depends on the empty base class optimisation.
You need a custom allocator but there's a catch: the allocator can't have any state or it'll change the binary layout of the vector object, so we end up 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 it run here

Related

Unexpected results with array and array as argument [duplicate]

This question already has an answer here:
When passing an array to a function in C++, why won't sizeof() work the same as in the main function?
(1 answer)
Closed 1 year ago.
Forgive me for this possibly dumb question. Consider this:
int foo(int* arr) {
std::cout << arr << "(" << sizeof(arr) << ")";
}
int main()
{
int x[] = {0, 1, 2, 3, 4};
foo(x);
std::cout << " " << x << "(" << sizeof(x) << ")";
}
Output: 0x7c43ee9b1450(8) 0x7c43ee9b1450(20) - Same address, different size.
My understanding is that the function argument is an address specific to the first element of the array, so the size is 8 bytes, and the same should be true for the variable in main too; So how come the size of the variable outside of the function represent the whole array (4 bytes int times 5 elements = 20)? How could I possibly determine from inside the function how large an array actually is?
This is because the types are not the same inside and out side the function.
If you make sure the type is the same inside and outside the function you should get the same result.
int foo(int (&arr)[5])
{
std::cout << arr << "(" << sizeof(arr) << ")";
return 0;
}
The problem is that arrays decay into pointers at the drop of a hat. So if you pass an array to a function it will easily be converted into a pointer. That is what is happening here.
int foo(int* arr)
// ^^^^ Notice this is not an array.
// It is simply a pointer to an integer
// The array has decayed into a pointer to the
// first element in the array.
{
std::cout << arr << "(" << sizeof(arr) << ")";
return 0;
}
How could I possibly determine from inside the function how large an array actually is?
This is actually a real problem with C. In C they solved this by getting you to pass the size of the array as a second parameter:
int foo(int* arr, std::size_t size);
Then call it from main as:
foo(arr, sizeof(arr)/sizeof(arr[0])); // This always works as it done
// at compile time and not runtime
In C++ we don't usually use C-arrays but prefer std::vector or std::array as the size is easily retrievable. Generally we use a container type C as they are duck types of Container:
template<typename C>
int foo(C& container)
{
std::cout << "(" <<container.size() << ")";
return container.size();
}
When passing an array like that you loose ALL the size information.
So the called function is flying blind with regard to the array size.
In C++ is makes much more sense to use std::array (fixed size arrays), and std::vector (changing size arrays). It is much clearer what your intent is when you pass them to functions. There will be less mistakes and less memory access issues in your code.
I hope I don't scare you too much with the template version.
The vector variant is more easy, but may use a bit more memory at runtime.
#include <array>
#include <vector>
#include <iostream>
template<size_t N>
size_t foo(const std::array<int,N>& arr)
{
for (const auto n : arr) std::cout << n << " ";
std::cout << "(" << arr.size() << ")" << std::endl;
return arr.size();
}
size_t foo(const std::vector<int>& arr)
{
for (const auto n : arr) std::cout << n << " ";
std::cout << "(" << arr.size() << ")" << std::endl;
return arr.size();
}
int main()
{
std::array<int,5> x{ 0, 1, 2, 3, 4 };
std::vector<int> y{ 0, 1, 2, 3, 4 };
auto size_x = foo(x);
auto size_y = foo(y);
}

How, if possible, can I use variadic templates to make a function that prints multiple std::vectors of any type side by side?

I am trying to write a function printV() that takes some number of vectors (probably less than six) of any built-in type printable with cout, passed as const reference and prints them side by side, so that compareV(v1, v2, v3) would produce the output:
v1[1], v2[1], v3[1]
v1[2], v2[2], v3[3]
v1[3], v2[3], v3[3]
Here is the function I'm using to print a single vector:
template <typename T>
void printV(const std::vector<T> &vec)
{
for (int i = 0; i < vec.size(); i++)
{
std::cout << i << ": " << vec[i] << std::endl;
}
}
I would like to adapt this function to print multiple vectors, side by side. However, I don't know if it's possible to do something like:
template <typename... T>
void printV(const std::vector<T>... &vec)
{
//code that expands (vec...) into vec1, vec2, vec3 etc. the part I'm unsure about
for(int i = 0; i < vec1.size(); i++)// the size of the first vector will be the same as the other two
{
std::cout << i << ": " << vec1.at(i) << ", " << vec2.at(i) << ", " << vec3.at(i) << std::endl;
}
}
I would have to use some sort of utility function and an intermediate string variable to get around the fact that the pramaters cannot be accessed together in the same scope.
This microsoft documentation article, as well as section 3.4.4 of "The C++ Programming Language" Recommend using recursion to seperate the first argument from all of those after it and making an overload of the function for the case with no parameters:
// From Section 3.4.4 of "The C++ Programming Language"
template<typename T, typename ... Tail>
void f(T head, Tail... tail)
{
g(head); // do something to head
f(tail...); // try again with tail
}
void f() { } // do nothing
which would prevent access to multiple parameters in a single scope. How might I get around this?
Any suggestions or general advice is greatly appreciated, Thanks!
You can do this:
template <typename firstT, typename... T>
void printV(const std::vector<firstT>& first, const std::vector<T>& ... vec)
{
for(int i = 0; i < first.size(); i++)
{
std::cout << i << ": " << first.at(i);
( (std::cout << ' ' << vec.at(i)), ... );
std::cout << std::endl;
}
}
Live: https://godbolt.org/z/dq5P64

Accessing references to existing object in a range based for loop with structured binding

I am struggling to find an easy solution to alter some already existing objects.
Lets assume I have the following pairs
std::pair<int, foo> p1 = {1,foo()};
std::pair<int, foo> p2 = {2,foo()};
std::pair<int, foo> p3 = {3,foo()};
with foo being a class with the method alter().
And I would want to alter only the foo-object of each of those pairs. Then I could do so via:
p1.second.alter();
p2.second.alter();
p3.second.alter();
Or, in my opinion a tiny bit less redundant:
for(auto&& p :
std::vector<std::reference_wrapper<std::pair<int, foo>>> {p1, p2, p3})
{
auto&& [pi, pfoo] = p.get();
pfoo.alter();
}
But what I would really like to have would be something like:
for(auto&& [pi, pfoo] : {p1, p2, p3})
{
pfoo.alter();
}
which obviously does not work as pfoo is only a copy then.
So is there any way to not copy p1, p2 and p3 in that loop?
I am of course aware that one could start off with e.g. a vector holding the three pairs, but is there any other way?
You could write a loop that iterates over the addresses of the objects, like this:
for (auto *p : {&p1, &p2, &p3})
p->second.alter();
Here's a demo.
You can do some magic with parameter packs:
struct S
{
int x = 0;
void alter() {x++;}
};
template<typename... Args>
void foo(std::pair<int, Args>&... args)
{
((args.second.alter()),...);
}
int main()
{
std::pair<int, S> a, b{0, {10}}, c{0, {100}};
std::cout << "Pre foo(): " << a.second.x << " " << b.second.x << " " << c.second.x << "\n";
foo(a, b, c);
std::cout << "Post foo(): " << a.second.x << " " << b.second.x << " " << c.second.x << "\n";
}
// output:
Pre foo(): 0 10 100
Post foo(): 1 11 101
I'm afraid I couldn't get it to work without template as parameter (i.e. to make it only accept S as second type in pair), perhaps this answer will inspire someone to do better.

Simple C++ Program Compiled without Optimization by GCC doesn't Generate Expected Results

Today when I tried to compile a very simple C++ program using GCC7, I met a very strange problem: the program didn't add any elements to a vector in the constructor, when compiled without optimization (e.g. -O0/-Og) by the GCC 7.2.1 from Devtoolset-7 on Red Hat Enterprise Linux 7. Only when the optimization switch was added (e.g. -O/-O1/-O2/...), the compiled binary can generated expected results. But why is this happening?
By the way:
without optimization, the binaries compiled by GCC 7.2.1 on RHEL7 and GCC 7.3.0 on Mac (Homebrew version) behaved differently: the former didn't add any elements, while the latter add 2 elements.
clang doesn't have this problem no matter the optimization is turned on or not)
The code:
#include <vector>
#include <utility>
#include <iostream>
class Container
{
std::vector<std::size_t> elements;
public:
Container() {}
Container(std::size_t n)
{
std::cout << "Creating " << n << " elements:";
for(int i; i<n; ++i)
{
std::cout << " " << i+1;
elements.push_back(i+1);
}
std::cout << '\n';
}
Container(Container& c) : elements{c.elements} {}
Container(Container&& c) : elements{std::move(c.elements)} {}
virtual ~Container() noexcept {}
Container& operator=(const Container& c)
{
if(this != &c)
{
elements = c.elements;
}
return *this;
}
Container& operator=(Container&& c)
{
if(this != &c)
{
elements = std::move(c.elements);
}
return *this;
}
void print()
{
std::cout << "Container has " << elements.size() << " elements:" << '\n';
for(auto it=elements.cbegin(); it!=elements.cend(); ++it)
{
if(it == elements.cbegin()) std::cout << *it;
else std::cout << ", " << *it;
}
if(elements.size()>0) std::cout << '\n';
}
};
Container makeContainer()
{
std::cout << "Inside makeContainer()" << '\n';
std::cout << "Before:" << '\n';
Container c(3);
c.print();
std::cout << "Temporary:" << '\n';
Container c_tmp(3);
c_tmp.print();
c = c_tmp;
std::cout << "After:" << '\n';
c.print();
return c;
};
int main()
{
Container c = makeContainer();
std::cout << "Inside main()" << '\n';
c.print();
return 0;
}
Expected output:
Inside makeContainer()
Before:
Creating 3 elements: 1 2 3
Container has 3 elements:
1, 2, 3
Temporary:
Creating 3 elements: 1 2 3
Container has 3 elements:
1, 2, 3
After:
Container has 3 elements:
1, 2, 3
Inside main()
Container has 3 elements:
1, 2, 3
Actual output:
Inside makeContainer()
Before:
Creating 3 elements:
Container has 0 elements:
Temporary:
Creating 3 elements:
Container has 0 elements:
After:
Container has 0 elements:
Inside main()
Container has 0 elements:
If you do not assign a value to a variable its state is indeterminate.
In debug mode the compiler can put the value zero to initialize indeterminate values to help with debugging. But in release this extra unasked for initialization will not happen.
for(int i; i<n; ++i) // Here you have declared `i` but not initialized it.
As a result in release mode the value is probably larger than n and thus no elements are inserted.
Note: It is UB to read the value of an initialized variable (so your whole program can do anything).

Read and write different types in vector

How can I pack in a vector several different primitive data types as well as strings to examine the contents then?
(In Java, this went via Object [] objects = {1.0, "Hello", - 42, 'b'})
The task is as follows:
Given the following array: [3.0,42, "Monkey", 7.2, b]
This array is to be passed to a method that outputs the contents of the array on the console. If it is a string, each letter of the string should be added as an ASCII value in the same variable, and finally returned as an int on the console. With char exactly the same.
I know from today as I create a vector so with std::vector<double> numbers = {1.0,2.0}; How to write functions and how to access the indexes numbers[i]; as well as the length of the vector numbers.size().
How can I solve this problem now? Since I have unfortunately found no simple <- solution for the multiple types in a vector.
Thanks in advance :)
C++ does not do type erasure the same way that Java does. To create a heterogeneous container (which is the technical term for what you're trying to do) you'll need to make extensive use of std::any or std::variant, which are new classes introduced with C++17.
std::vector<std::any> values{1.0, "Hello", -42, 'b'};
for(auto & any : values) {
int * i;
if(val = std::any_cast<int>(&any)) std::cout << "int: " << *i << std::endl;
const char ** s;
if(s = std::any_cast<const char *>(&any)) std::cout << "string-literal: " << *s << std::endl;
double * d;
if(d = std::any_cast<double>(&any)) std::cout << "double: " << *d << std::endl;
char * c;
if(c = std::any_cast<char>(&any)) std::cout << "char: " << *c << std::endl;
}
Note how messy that code is. Not least of which because many people would desire "hello" to be stored as a std::string object, but this can't be done unless the user expressly designates it as such:
std::vector<std::any> values{1.0, std::string{"Hello"}, -42, 'b'};
At any rate, my personal opinion is that the use of std::variant would be a much better fit, as you can make it much clearer how the container is meant to be used, and you can avoid the dynamic allocations associated with std::any:
typedef std::variant<std::string, char, double, int> my_variant;
struct visitor {
void operator()(std::string const& v) const {
std::cout << "std::string: " << v<< std::endl;
}
void operator()(double const& v) const {
std::cout << "double: " << v << std::endl;
}
void operator()(int const& v) const {
std::cout << "int: " << v << std::endl;
}
void operator()(char const& v) const {
std::cout << "char: " << v << std::endl;
}
};
int main() {
std::vector<my_variant> values{1.0, "Hello", -42, 'b'};
for(my_variant & variant : values) {
std::visit(visitor{}, variant);
}
return 0;
}
We can even make the variant version a lot simpler with auto lambdas if we don't need to know the type:
typedef std::variant<std::string, char, double, int> my_variant;
int main() {
std::vector<my_variant> values{1.0, "Hello", -42, 'b'};
for(my_variant & variant : values) {
std::visit(
[](auto const& val) {std::cout << "Some unknown type: " << val << std::endl;},
variant
);
}
return 0;
}
I haven't run this through my compiler, but this should give a pretty good sense of how to accomplish this kind of task in C++.
If you don't have access to C++17, you can use boost.any and boost.variant, which I'm reasonably sure are both header-only libraries, and thus easy to import into your project.