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++;});
Related
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
I have tried to access the members of a class Part that are vector elements of type integer inside the vector tasks.
#include <iostream>
#include <vector>
using namespace std;
class Part{
vector<int> tasks;
public:
void setTasks(void);
void getTasks(void);
};
void Part::setTasks(void){
vector<int>::iterator it;
int i=1;
for (it = this->tasks.begin(); it != this->tasks.end(); ++it)
{
*it=i;
i=i+1;
}
}
void Part::getTasks(void){
vector<int>::iterator it;
for (it = this->tasks.begin(); it != this->tasks.end(); ++it)
cout<<*it<<"\t";
}
int main()
{
Part one;
one.setTasks();
one.getTasks();
return 0;
}
I am simply trying to access the values and print them yet failing. There is no compilation error. In run-time, nothing is outputted in the terminal. Where is the error?
A default constructed vector has zero size, so the for loop in setTasks is never entered (since the begin() and end() iterators are the same at that point). If you set an initial size to the vector your code will work as intended. For instance, try adding the following at the beginning of setTasks
tasks.resize(10); // sets vector size to 10 elements, each initialized to 0
Another way to write that function would be
#include <numeric>
...
void Part::setTasks(void){
tasks.resize(10);
std::iota(tasks.begin(), tasks.end(), 1); // requires C++11
}
You could also set the initial size of the vector in the default constructor of Part if you wanted to. In that case add the following public constructor
Part() : tasks(10)
{}
Yet another way to achieve setting the size upon construction would be
class Part{
vector<int> tasks = vector<int>(10); // requires C++11
The size of your vector is 0 when you call setTasks(). Your iterator doesn't get you into the for loop at all. You need to think about what exactly you want your setTasks() to do. How many elements of the vector did you intend to set? You should either define your vector with that size, or use that many number of push_backs instead to set your vector to the desired value.
Your vector is empty. Try giving it a size. For example, vector<int> tasks(10). See option 3 in this.
Alternatively, you can use a "back-insert" iterator (#include <iterator>), which internally calls std::vector::push_back, like this:
void Part::setTasks(void){
auto back_it = std::back_inserter(tasks);
for(int i = 0; i < 10; ++i)
*back_it++ = i;
}
This kind of iterator is especially useful in algorithms where your destination size is unknown. Although if you know the size in advance, you should use reserve/resize or specify the size at construction, since push-ing back into a vector can sometimes be slow due to re-allocation.
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.
I'm trying to do this:
for(int k=0; k<context.size(); k++)
{
cc_no_issue[k]=0;
}
Can someone tell me how I can do that globally? Whenever I try I get these errors:
expected unqualified-id before "for"
k does not define a type
k does not define a type
This will do:
long cc_no_issue[100]={0};
And this is the proper initialization.
Note: this will initialize all the contents to 0.
This sentence:
long cc_no_issue[100]={1,2};
will set cc_no_issue[0] to 1, cc_no_issue[1] to 2, and the rest to 0. You could see the link above for more information.
If you have a global array of a basic type,
int some_array[1000];
It will automatically be initialized to zero. You do not have to initialize it. If you do need to run initialization code, you can do a hack like the following (in C++):
struct my_array_initializer {
my_array_initializer() {
// Initialize the global array here
}
};
my_array_initializer dummy_variable;
If you are on GCC (or Clang), you can execute code before main with the constructor attribute:
__attribute__((constructor))
void initialize_array()
{
// Initialize the global array here
}
All global variables (variables at file scope) are by default initialized to zero since they have static storage duration (C99 6.7.8.10). So strictly speaking, you needn't initialize them to zero, the C standard guarantees that they are zero by default.
It is good programming practice to initialize them explicitly however, as mentioned in the answer by Ziyao Wei.
No, you can't have code outside of functions.
You can put it inside some function and call that from the start of main.
One way is to add a global function that:
Checks if the array is initialized
Initializes the array if it wasn't initialized
Returns the array
Example Code:
int* get_cc_no_issue()
{
if(!kIsMyArrayInitialized)
{
/* todo: somehow get "context" globally... */
for(int k = 0; k < context.size(); k++)
{
cc_no_issue[k] = 0;
}
kIsMyArrayInitialized = true;
}
return cc_no_issue;
}
This is most useful if you want non-zero initialization.
For zero-initialization, see this answer to another question:
Is global memory initialized in C++?
You can put the array in the constructor of a global object.
int cc_no_issue[256];
struct Init {
Init(int a, unsigned int size)
{
memset(a, 0, size);
}
};
Init arr(cc_no_issue, sizeof(cc_no_issue));
As #Bo Persson, do it in a function instead. But, there is already an algorithm that does it for you in C++. No need to write a hand written loop.
std::fill(cc_no_issue, cc_no_issue+context.size(); 0) ;
More info on std::fill
Response to your comment:
To increment every element, you can make use of std::for_each passing a function object as the third argument.
#include <iostream>
#include <algorithm>
using namespace std;
void incrementHelper( int& a ){
++a;
}
int main(){
int ar[] = { 1,2,3,4,5 };
for_each(ar, ar+5, incrementHelper );
for( int i=0; i<sizeof(ar)/sizeof(ar[0]); ++i ){
cout << ar[i] << endl;
}
return 0;
}
Ouput:
2
3
4
5
6
for_each(ar, ar+5, incrementHelper );
For each element in the array, the algorithm is going to call the function, incrementHelper. In C terminology,to say, it serves as a call back for each element in the array. Now the call back function, receives the passed element by reference. So, modifying the reference will modify the referrent also. See the online demo.
You need to decide on the language. The machanisms for this are different in C and C++. Basically C has no method of running code before your main function starts, so you cannot do complex initialisation of an array in C. In C++ you do have some options, one is to stop using a bare array (which is a C construct anyway) and instead wrap your array inside a class, and do the initialisation inside the class constructor.
CC cc_no_issue;
class CC
{
public:
CC()
{
// initialisation of array goes here
}
private:
int array[100];
};
Another way it to use a vector, and write a function to initialise the vector.
std::vector<int> cc_no_issue = init_vector();
std::vector<int> init_vector()
{
std::vector<int> tmp;
// initialisation of tmp goes here
return tmp;
}
This question already has answers here:
Initialization of all elements of an array to one default value in C++?
(12 answers)
Closed 4 months ago.
I'm trying to initialize an int array with everything set at -1.
I tried the following, but it doesn't work. It only sets the first value at -1.
int directory[100] = {-1};
Why doesn't it work right?
I'm surprised at all the answers suggesting vector. They aren't even the same thing!
Use std::fill, from <algorithm>:
int directory[100];
std::fill(directory, directory + 100, -1);
Not concerned with the question directly, but you might want a nice helper function when it comes to arrays:
template <typename T, size_t N>
T* end(T (&pX)[N])
{
return pX + N;
}
Giving:
int directory[100];
std::fill(directory, end(directory), -1);
So you don't need to list the size twice.
I would suggest using std::array. For three reasons:
1. array provides runtime safety against index-out-of-bound in subscripting (i.e. operator[]) operations,
2. array automatically carries the size without requiring to pass it separately
3. And most importantly, array provides the fill() method that is required for
this problem
#include <array>
#include <assert.h>
typedef std::array< int, 100 > DirectoryArray;
void test_fill( DirectoryArray const & x, int expected_value ) {
for( size_t i = 0; i < x.size(); ++i ) {
assert( x[ i ] == expected_value );
}
}
int main() {
DirectoryArray directory;
directory.fill( -1 );
test_fill( directory, -1 );
return 0;
}
Using array requires use of "-std=c++0x" for compiling (applies to the above code).
If that is not available or if that is not an option, then the other options like std::fill() (as suggested by GMan) or hand coding the a fill() method may be opted.
If you had a smaller number of elements you could specify them one after the other. Array initialization works by specifying each element, not by specifying a single value that applies for each element.
int x[3] = {-1, -1, -1 };
You could also use a vector and use the constructor to initialize all of the values. You can later access the raw array buffer by specifying &v.front()
std::vector directory(100, -1);
There is a C way to do it also using memset or various other similar functions. memset works for each char in your specified buffer though so it will work fine for values like 0 but may not work depending on how negative numbers are stored for -1.
You can also use STL to initialize your array by using fill_n. For a general purpose action to each element you could use for_each.
fill_n(directory, 100, -1);
Or if you really want you can go the lame way, you can do a for loop with 100 iterations and doing directory[i] = -1;
If you really need arrays, you can use boosts array class. It's assign member does the job:
boost::array<int,N> array; // boost arrays are of fixed size!
array.assign(-1);
It does work right. Your expectation of the initialiser is incorrect. If you really wish to take this approach, you'll need 100 comma-separated -1s in the initialiser. But then what happens when you increase the size of the array?
use vector of int instead a array.
vector<int> directory(100,-1); // 100 ints with value 1
It is working right. That's how list initializers work.
I believe 6.7.8.10 of the C99 standard covers this:
If an object that has automatic
storage duration is not initialized
explicitly, its value is
indeterminate. If an object that has
static storage duration is not
initialized explicitly, then:
if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned)
zero;
if it is an aggregate, every member is initialized (recursively) according
to these rules;
if it is a union, the first named member is initialized (recursively)
according to these rules.
If you need to make all the elements in an array the same non-zero value, you'll have to use a loop or memset.
Also note that, unless you really know what you're doing, vectors are preferred over arrays in C++:
Here's what you need to realize about containers vs. arrays:
Container classes make programmers more productive. So if you insist on using arrays while those around are willing to use container classes, you'll probably be less productive than they are (even if you're smarter and more experienced than they are!).
Container classes let programmers write more robust code. So if you insist on using arrays while those around are willing to use container classes, your code will probably have more bugs than their code (even if you're smarter and more experienced).
And if you're so smart and so experienced that you can use arrays as fast and as safe as they can use container classes, someone else will probably end up maintaining your code and they'll probably introduce bugs. Or worse, you'll be the only one who can maintain your code so management will yank you from development and move you into a full-time maintenance role — just what you always wanted!
There's a lot more to the linked question; give it a read.
u simply use for loop as done below:-
for (int i=0; i<100; i++)
{
a[i]= -1;
}
as a result as u want u can get
A[100]={-1,-1,-1..........(100 times)}
I had the same question and I found how to do, the documentation give the following example :
std::array<int, 3> a1{ {1, 2, 3} }; // double-braces required in C++11 (not in C++14)
So I just tried :
std::array<int, 3> a1{ {1} }; // double-braces required in C++11 (not in C++14)
And it works all elements have 1 as value. It does not work with the = operator. It is maybe a C++11 issue.
Can't do what you're trying to do with a raw array (unless you explicitly list out all 100 -1s in the initializer list), you can do it with a vector:
vector<int> directory(100, -1);
Additionally, you can create the array and set the values to -1 using one of the other methods mentioned.
Just use this loop.
for(int i =0 ; i < 100 ; i++) directory[i] =0;
the almighty memset() will do the job for array and std containers in C/C++/C++11/C++14
The reason that int directory[100] = {-1} doesn't work is because of what happens with array initialization.
All array elements that are not initialized explicitly are initialized implicitly the same way as objects that have static storage duration.
ints which are implicitly initialized are:
initialized to unsigned zero
All array elements that are not initialized explicitly are initialized implicitly the same way as objects that have static storage duration.
C++11 introduced begin and end which are specialized for arrays!
This means that given an array (not just a pointer), like your directory you can use fill as has been suggested in several answers:
fill(begin(directory), end(directory), -1)
Let's say that you write code like this, but then decide to reuse the functionality after having forgotten how you implemented it, but you decided to change the size of directory to 60. If you'd written code using begin and end then you're done.
If on the other hand you'd done this: fill(directory, directory + 100, -1) then you'd better remember to change that 100 to a 60 as well or you'll get undefined behavior.
If you are allowed to use std::array, you can do the following:
#include <iostream>
#include <algorithm>
#include <array>
using namespace std;
template <class Elem, Elem pattern, size_t S, size_t L>
struct S_internal {
template <Elem... values>
static array<Elem, S> init_array() {
return S_internal<Elem, pattern, S, L - 1>::init_array<values..., pattern>();
}
};
template <class Elem, Elem pattern, size_t S>
struct S_internal<Elem, pattern, S, 0> {
template <Elem... values>
static array<Elem, S> init_array() {
static_assert(S == sizeof...(values), "");
return array<Elem, S> {{values...}};
}
};
template <class Elem, Elem pattern, size_t S>
struct init_array
{
static array<Elem, S> get() {
return S_internal<Elem, pattern, S, S>::init_array<>();
}
};
void main()
{
array<int, 5> ss = init_array<int, 77, 5>::get();
copy(cbegin(ss), cend(ss), ostream_iterator<int>(cout, " "));
}
The output is:
77 77 77 77 77
Just use the fill_n() method.
Example
int n;
cin>>n;
int arr[n];
int value = 9;
fill_n(arr, n, value); // 9 9 9 9 9...
Learn More about fill_n()
or
you can use the fill() method.
Example
int n;
cin>>n;
int arr[n];
int value = 9;
fill(arr, arr+n, value); // 9 9 9 9 9...
Learn More about fill() method.
Note: Both these methods are available in algorithm library (#include<algorithm>). Don't forget to include it.
Starting with C++11 you could also use a range based loop:
int directory[10];
for (auto& value: directory) value = -1;