How to directly use vector as parameter in a function? - c++

I know how to initilize a new vector before using it, but how to convenitently use it as paramter in a function?
For example, when I init v1, it can get result in the end, but when I use v2, it shows error :cannot use this type name.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> Add(vector<int>&nums, int target)
{
cout << nums[0] + target;
}
};
int main(){
Solution Sol1;
vector <int> v1 {1,2,3};
Sol1.add(v1, 8);
Sol1.add(vector <int> v2{4,5,6}, 8);
}
Besides, I tried to correct v2 as Sol1.add(vector <int> {4,5,6}, 8); However, it shows error: The initial value of a non-constant reference must be an left value

The problem you are having has nothing to do with vector.
Sol1.add(vector<int> v2{4,5,6}, 8);
Here, it seems like you are trying to declare an object name v2 in the middle of this expression, which isn't something you can do in C++.
However, you can create a unnamed temporary object in the middle of it like:
Sol1.add(vector<int>{4,5,6}, 8);
or even:
Sol1.add({4,5,6}, 8);
But now you would face a different problem, like you mentioned:
The initial value of a non-constant reference must be an left value
The reason for that is you can't create a reference to a temporary object. To solve it, you can either copy the vector to your function, by changing the signature of your add function:
vector<int> add(vector<int> nums, int target)
{
⋮
}
However, this solution need to copy the entire vector to the function, hence it might be quite slow if your vector is large. Another way is to change the signature to const reference of a vector, which can bond to a temporary object. The downside is that you will not be able to modify the object inside the function, if you were looking to do that:
vector<int> add(const vector<int>& nums, int target)
{
⋮
}

This is one of the ways.
But in this way you will not be able use the variable v2
Sol1.add({4,5,6}, 8);
For more details read this Question

Related

Vector parameter in a function doesn't seem to actually apply to input?

I have a vector variable named intVec, and I have a function named pushBack, that accepts a vector of type integer just like intVec, but when I actually pass that vector into the function in order to push_back the x parameter, nothing seems to happen.
Output expected from intVec.size() is 1
Output given from intVec.size() is 0
I'm genuinely confused as to what I'm doing incorrectly here.
Perhaps I'm missing something extremely obvious.
#include <vector>
std::vector<int> intVec;
void pushBack(int x, std::vector<int> vec) {
vec.push_back(x);
}
int main() {
pushBack(10, intVec);
std::cout << intVec.size();
}
That is because you pass the vector by value instead of by reference (or pointer).
This means, that when you call the function, the vector you call 'push_back' on is actually an independent copy of the original vector, which get deallocated upon leaving the function.
Try this header instead:
void pushBack(int x, std::vector<int> &vec) {
vec.push_back(x);
}
The & tells the compiler to pass by reference, meaning that whatever you do to vec, you also do to the vector you originally passed.
Write pushBack as below:
void pushBack(int x, std::vector<int>& vec) {
vec.push_back(x);
}
The only difference is that here vec is being passed by reference. In your code it is being passed by value.

Using vector::back() to modify vector element

I have the following struct:
#include <string>
#include <vector>
struct A {
std::string name;
int id;
};
And a vector containing A elements:
std::vector<A> a_vector;
I am trying to append an element to the vector and change its values using the following:
void test()
{
A a;
get_a(a);
//Up to this point I thought modifying this a object would mean modifying the back element of the vector. But it doesn't work as planned, doing this:
a.id = 2; //Doesn't modify the id of the element in the vector.
}
where get_a is defined as : (The code is simplified, in the real one I really need to pass a as argument and not get it as return)
void get_a(A& a) //This function normally assigns a in different ways
{
a_vector.emplace_back();
a = a_vector.back();
}
How can I do to have the a element be the same as the one in the vector? Do I really have to use pointers?
A a;
a = a_vector.back();
Here you're copy-assigning a_vector.back() to a. This is not a reference, so modifying a will not modify the element inside the vector.
You want this instead:
A& a = a_vector.back();
If you cannot immediately initialize your reference with a_vector.back(), consider using a pointer...
A* a;
// ...
a = &a_vector.back();
// ...
something(*a);
...or an index:
std::size_t a_idx;
// ...
a_idx = a_vector.size() - 1;
// ...
something(a_vector[a_idx]);
The pointer will work fine if you know that the vector won't get resized. If the vector resize, iterators and pointers will be invalidated.
The index will work fine even if the vector gets resized, as long as the elements are not removed/shifted around.
You need a reference to the object:
auto& a = a_vector.back();
Or, in a more compact manner:
a_vector.back().id = 2;
You're holding a copy, not the original object. That is why the object in vector does not get modified.
Answer to edited question: references can be assigned only during declaration. What you want is probably std::reference_wrapper, but anyway, please don't use it unless you have to.

How to store references to objects from one vector in another vector in C++?

I've got a vector std::vector<MyClass> myclass_vec(10) with 10 initialized objects of MyClass. Now I would like to loop over this vector and store a reference to every MyClass object in another vector std::vector<MyClass> myclass_vec_refs. The reason why I would like to store references is so because I don't have to copy the objects and obviously, refer to the same object as in myclass_vec.
For some reason, this doesn't work out as aspected. Do I have to declare std::vector<&MyClass> myclass_vec_refs like so?
As I was looking through other questions asked here I read about std::unique_ptr. If I change std::vector<std::unique_ptr<MyClass>> myclass_vec(10) then I wouldn't able to have a reference or pointer in myclass_vec_refs since they are declared unique. Correct me please if I'm mistaken.
Another approach was using std::shared_ptr. Since it holds a reference counter I would be able to have myclass_vec_refs point to objects in myclass_vec, but I read this introduces quite some overhead and share_ptr should only be used as a last resort.
I also don't know if referencing like I'm attempting works out. What happens if an object in myclass_vec is deleted? Is the myclass_vec_refs vector resized by -1 since the object doesn't exist anymore or is it just pointing to bad memory?
Is it possible to emplace_back a reference in the myclass_vec_refs vector? Since this creates the object in-place I guess this doesn't work and only push_back can be used?
You cannot make a vector of references.
Why?
A reference must refer to an actual object at all times, and vectors by design must be able to create "empty" objects (i.e. default constructor) dynamically for you.
You can however create a vector of pointers.
If the other vector is modified in any way, your pointers will become invalid.
If this is a problem to you, use a map or set instead.
As answered here: Strange Template Deduction
The trick is to use std::reference_wrapper<>
#include <algorithm>
#include <iostream>
#include <vector>
template<typename container_ty_, class Comp>
auto where(container_ty_& V, Comp&& comp)
{
using value_type = typename container_ty_::value_type;
using reference =
std::conditional_t<
std::is_const<container_ty_>::value,
std::reference_wrapper<const value_type>,
std::reference_wrapper<value_type>
>;
std::vector<reference> cursor;
for(auto& VAL : V)
if(comp(VAL))
cursor.push_back(VAL);
return cursor;
}
int main(int argc, char** argv) {
std::vector<int> tVect = {0, 5, 2, 1, 7, 9};
//Why must std::vector<int> be passed...
auto vec = where(tVect, [](const int& V) -> bool { return V > 5; });
std::for_each(vec.begin(), vec.end(), [] (int& v) { std::cout << v++ << std::endl; });
std::cout << std::endl;
std::for_each(tVect.begin(), tVect.end(), [](const int& v) { std::cout << v << std::endl; });
}

Initialize a C++ vector with a variable inital value

I was coding up a Union find data structure , and was trying to initialize the parent vector with a value parent[i]=i, Is there a way in c++ to initialize the vector like this , that is declaring a vector of size N , and not assigning fixed values to each element, rather position dependent value to each element. (without using any obvious for loops)
This is what I was looking for:
std::vector<int> parent(Initializer);
where Initializer is some class or a function.
To try out my hand a bit, I wrote this:
#include <iostream>
#include <vector>
using namespace std;
class Initializer {
private:
static int i;
public:
int operator() ()
{
return i++;
}
};
int main()
{
vector<int> parent(Initializer);
cout << parent[0];
return 0;
}
However I think I have messed up my concepts pretty bad here, and I am not getting what the declaration means, or what it is doing.
Please answer both the questions,
(1) How to initialize a vector with variable initial values.
(2) What exactly is the code I wrote doing?
This is a function declaration:
vector<int> parent(Initializer);
Becasue Initializer is a type name, you declared a function parent that takes Initializer as a (unnamed) parameter and returns vector<int>. See Most vexing parse.
To do what you want, you can do this:
std::vector<int> parent(N); // where N is the size you want
std::iota(parent.begin(), parent.end(), 0); // fill it with consecutive values
// starting with 0
There's std::generate algorithm that you can use to save result of a function (or function object) in a range:
std::generate(parent.begin(), parent.end(), Initializer());
Live demo.
There are several alternatives. If you want to initialize the vector with increasing values, then you can use std::iota.
std::vector<int> vec(size);
std::iota(std::begin(vec), std::end(vec), 0);
If you want something more general you could use std::generate.
std::vector<int> vec(size);
int n = 0;
std::generate(std::begin(vec), std::end(vec), [&n]() {return n++;});

How to pass a vector to another vector push back? (without creating a extra variable to pass)

Well I am questioning myself if there is a way to pass a vector directly in a parameter, with that I mean, like this:
int xPOS = 5, yPOS = 6, zPOS = 2;
//^this is actually a struct but
//I simplified the code to this
std::vector <std::vector<int>> NodePoints;
NodePoints.push_back(
std::vector<int> {xPOS,yPOS,zPOS}
);
This code ofcourse gives an error; typename not allowed, and expected a ')'
I would have used a struct, but I have to pass the data to a Abstract Virtual Machine where I need to access the node positions as Array[index][index] like:
public GPS_WhenRouteIsCalculated(...)
{
for(new i = 0; i < amount_of_nodes; ++i)
{
printf("Point(%d)=NodeID(%d), Position(X;Y;Z):{%f;%f;%f}",i,node_id_array[i],NodePosition[i][0],NodePosition[i][1],NodePosition[i][2]);
}
return 1;
}
Ofcourse I could do it like this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//local
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
or this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//global
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
x.clear()
but then I'm wondering which of the two would be faster/more efficient/better?
Or is there a way to get my initial code working (first snippet)?
Use C++11, or something from boost for this (also you can use simple v.push_back({1,2,3}), vector will be constructed from initializer_list).
http://liveworkspace.org/code/m4kRJ$0
You can use boost::assign as well, if you have no C++11.
#include <vector>
#include <boost/assign/list_of.hpp>
using namespace boost::assign;
int main()
{
std::vector<std::vector<int>> v;
v.push_back(list_of(1)(2)(3));
}
http://liveworkspace.org/code/m4kRJ$5
and of course you can use old variant
int ptr[1,2,3];
v.push_back(std::vector<int>(ptr, ptr + sizeof(ptr) / sizeof(*ptr));
If you don't have access to either Boost or C++11 then you could consider quite a simple solution based around a class. By wrapping a vector to store your three points within a class with some simple access controls, you can create the flexibility you need. First create the class:
class NodePoint
{
public:
NodePoint( int a, int b, int c )
{
dim_.push_back( a );
dim_.push_back( b );
dim_.push_back( c );
}
int& operator[]( size_t i ){ return dim_[i]; }
private:
vector<int> dim_;
};
The important thing here is to encapsulate the vector as an aggregate of the object. The NodePoint can only be initialised by providing the three points. I've also provided operator[] to allow indexed access to the object. It can be used as follows:
NodePoint a(5, 6, 2);
cout << a[0] << " " << a[1] << " " << a[2] << endl;
Which prints:
5 6 2
Note that this will of course throw if an attempt is made to access an out of bounds index point but that's still better than a fixed array which would most likely seg fault. I don't see this as a perfect solution but it should get you reasonably safely to where you want to be.
If your main goal is to avoid unnecessary copies of vector<> then here how you should deal with it.
C++03
Insert an empty vector into the nested vector (e.g. Nodepoints) and then use std::swap() or std::vector::swap() upon it.
NodePoints.push_back(std::vector<int>()); // add an empty vector
std::swap(x, NodePoints.back()); // swaps contents of `x` and last element of `NodePoints`
So after the swap(), the contents of x will be transferred to NodePoints.back() without any copying.
C++11
Use std::move() to avoid extra copies
NodePoints.push_back(std::move(x)); // #include<utility>
Here is the explanation of std::move and here is an example.
Both of the above solutions have somewhat similar effect.