c++: std::vector of std::vector inside a struct - c++

I need to create a struct that sotres a
std::vector<std::vector<int>> that will contain 4 vectors of ints.
I tried the declaration I usually use for vector of vectors:
struct myStruct{
std::vector<std::vector<int>> myVector(4);
};
but, when I compile, I get this error:
myProgram.cpp:79:52: error: expected identifier before numeric constant
std::vector<std::vector<int>> myVector(4);
^
myProgram.cpp:79:52: error: expected ‘,’ or ‘...’ before numeric constant
I tried to declare the vector in the struct and then reserve 4 elements in the main(), in the following way:
struct myStruct{
std::vector<std::vector<int>> myVector;
};
int main(){
myStruct s;
s.myVector.reserve(4);
s.myVector[0].push_back(1);
return 0;
}
In this way it compiles without errors, but I get a segmentation violation as soon as I try to push_back.
What is the proper way to do this task? And why can't I use the first declaration to specify the size of myVector?
Thank you! :)

A default member initializer inside a class or struct must have an = token and/or {curly braces}.
std::vector<std::vector<int>> myVector{4};
[Note this would be trickier if the type were just std::vector<int>, since curly braces for a vector imply a sequence of elements. std::vector<int>{4} is a vector with size one whose one element is 4, not a vector of four zeroes. But here it's fine because {4} can't convert to std::initializer_list<std::vector<int>>, so that constructor overload isn't eligible, and the vector(size_type) constructor does win.]
The example program has undefined behavior because reserve does not change the size or create any elements. So s.myVector[0] is invalid since the vector is still empty. Remember, reserve is just a setup hint for the vector. Any valid program that uses reserve would still be valid if you removed all the reserve calls.
Using resize instead would do what you seem to mean: make the size of myVector equal to 4, by creating 4 empty element vectors. Then the push_back would add the number 1 to the first of those vectors, resulting in data {{1}, {}, {}, {}}.
int main(){
myStruct s;
s.myVector.resize(4);
s.myVector[0].push_back(1);
return 0;
}

struct myStruct {
std::vector<std::vector<int>> myVector{4};
};
int main() {
myStruct s;
s.myVector[0].push_back(1);
s.myVector[0].push_back(2);
s.myVector[0].push_back(3);
s.myVector[0].push_back(4);
s.myVector[1].push_back(11);
s.myVector[1].push_back(21);
s.myVector[1].push_back(31);
s.myVector[1].push_back(41);
cout << s.myVector[0][0] << " " << s.myVector[0][1] << " " << s.myVector[0][2] << " " << s.myVector[0][3] << " " << endl;
cout << s.myVector[1][0] << " " << s.myVector[1][1] << " " << s.myVector[1][2] << " " << s.myVector[1][3] << " " << endl;
return 0;
}
What is the proper way to do this task?
Hope this will answer your question.

Related

Is it Safe to Assign vector With operation= vector() in C++

Is it safe to assign vector later after initialization.
Let say i have a global vector variable. But i don't want to initialize the value at the beginning.
#include <iostream>
#include <vector>
using namespace std;
vector<int> globalVector;
int myNumber=123;
void setVector()
{
// Is it safe to set the vector as shown below ?
globalVector = vector<int>{1,2,3,4};
}
int main(int, char**) {
setVector();
for (int x=0; x<globalVector.size();x++)
{
cout << "Val = " << globalVector[x] << endl;
}
std::cout << "Hello, world! : " << myNumber << endl;
return 0;
}
on VSCode i can see some information said :
std::vector<int> &std::vector<int>::operator=(std::vector<int> &&__x)
+2 overloads
%Vector move assignment operator.
Parameters:
__x – A %vector of identical element and allocator types. The contents of __x are moved into this %vector (without copying, if the allocators permit it). Afterwards __x is a valid, but unspecified %vector. Whether the allocator is moved depends on the allocator traits.
The description said "move without copying". will the globalVector corrupt when the program exit from function setVector ?
Yes that is safe, although
The notation globalVector = {1,2,3,4}; is clearer.
It's not thread-safe.
Use globalVector.at(x) rather than globalVector[x] unless performance really matters, as the behaviour of the latter can be undefined for some values of x. In this particular case, a range-for loop would be better still: for (auto&& i: globalVector).
The description said "move without copying". will the globalVector corrupt when the program exit from function setVector ?
It means that operator= moved content of new vector without copy operation. The vector used for initialization is invalid after that operation. However it doesn't impact you since it is the object used only for initialization so is destroyed just after that.
Yes, it is totally safe, but I recommend you not to use global vector
instead write
int main() {
std::vector<int> globalVector = vector<int>{1,2,3,4};
for (int i=0; i<globalVector.size();i++) {
cout << "Val = " << globalVector.at(i) << '\n';
}
std::cout << "Hello, world! : " << myNumber << '\n';
return 0;
}

Accessing an element of a vector created dynamically

vector <int> * v = new vector <int>;
v -> push_back (1);
cout << v[0]<< endl; // error
Why can't I access the first element? I get this error
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream}' and 'std::vector')|
Why would you allocate a vector with new? The main point of using vectors is to avoid having to use new.
vector<int> v;
v.push_back(1);
cout << v[0] << endl;
If for some strange reason you decide you really must use a pointer, then you can do
vector<int>* v = new vector<int>;
v->push_back(1);
cout << (*v)[0] << endl;
But really, allocating a vector with new makes little sense.
Perhaps you were a Java programmer before you tried C++? If so then don't try to program C++ in a Java style, they are very different languages. You will get into a horrible mess if you do.
Because v is pointer to vector, but not reference or vector itself. Therefore v[0] gives you not what you likely expect. It gives you vector object itself. For which there is no stream output operator<< defined. You must use (*v)[0].
It's very unlikely that you need to dynamically allocate a vector like this, but if you do have a pointer to a vector:
vector<int>* v = new vector<int>;
then the correct syntax to invoke the member functions is:
// dereferencing the pointer and then using the member functions
(*v).push_back(1);
cout << (*v)[0] << endl;
or
// using -> with the correct names of the member functions
v->push_back(1);
cout << v->operator[](0) << endl;

Why can I still access vector data after resizing?

The following code doesn't throw an error:
int main()
{
typedef std::vector<int> intstack;
intstack mystack;
mystack.push_back(7);
mystack.push_back(8);
mystack.push_back(9);
mystack.pop_back();
std::cout << mystack.size(); //prints 2
std::cout << mystack[2]; // prints 9
return 0;
}
I would have thought the line std::cout << mystack[2] would throw an error because the vector has been resized by the pop_back operation. Why is the data still accessible? Is it because the data in the underlying array is still there and the vector pop_back operation only modifies the iterators?
std::vector operator[] does not perform range checks.
the at() member function does.
Your line std::cout << mystack[2] has undefined behavior.

Creating an array of classes not working

I'm trying to create an array of classes using a vector, but I think I'm getting the syntax wrong from instantiating the array. The error I'm getting is:
error: request for member 'setX' in objects[0], which is of non-class type 'std::vector'
#include <iostream>
#include <vector>
using std::cout;
class A {
public:
void setX(int a) { x = a; }
int getX() { return x; }
private:
int x;
};
int main() {
std::vector<A> *objects[1];
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
}
std::vector<A> objects; // declare a vector of objects of type A
objects.push_back(A()); // add one object of type A to that vector
objects[0].setX(5); // call method on the first element of the vector
With an asterisk and a square brackets, you are declaring an array of pointers to vectors instead of a vector. With std::vector<T> you do not need square brackets or an asterisk:
std::vector<A> objects(2); // 2 is the number of elements; Valid indexes are 0..1, 2 is excluded
objects[0].setX(5); // This will work
objects[1].setX(6);
The reason the compiler thought that you were trying to call setX on a vector is that the square bracket operator, overloaded by the vector, is also a valid operator on an array or a pointer.
An array and std::vector are two completely different container types. An array is actually a fixed-size block of memory, where-as a std:vector object is a dynamic sequential container type, meaning it can be dynamically "grown" and "shrunk" at run-time, and the object itself manages the memory allocation of the objects it owns. Their apparent similarities are that both can access members in O(1) complexity and can use the bracket syntax for accessing members.
What you want is something like the following:
int main()
{
//make a call to the std::vector<T> cstor to create a vector that contains
//two objects of type A
std::vector<A> objects(2);
//you can now access those objects in the std::vector through bracket-syntax
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
return 0;
}
here what you did is define an array with 1 element of type std::vector*, you may want to read more about vector and array first.
The correct way to define it is:
std::vector<A> objects(2);
or using pointers if that is what you intend to
std::vector<A*> objects(2);
objects[0] = new A();
objects[1] = new A();

Pointing to vectors

#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector <int> qwerty;
qwerty.push_back(5);
vector <int>* p = &qwerty;
cout << p[0]; //error: no match for 'operator<<' in 'std::cout << * p'
}
I'm generally unclear on how to use pointers with vectors, so I'm pretty mystified as to why this is not working. To my mind, this should print 5 to screen.
// either
cout << (*p)[0];
// or
cout << p->operator[](0);
Your 'cout' line is equivalent to:
cout << qwerty;
because p is a pointer to qwerty, which you then dereference with [0].
qwerty is a vector of type int, which can't be printed directly.
If you look at http://www.cplusplus.com/reference/stl/vector/ , you can see there is a class method for [] overload, so qwerty[0] would return an int.
So cout << qwerty[0]; would work.
To better understand what does "p[0]" mean, you can try the following statement:
cout << p[0][0];
this statement will enable you to print out "5" on the console. Because p[0] return the object reference "qwerty", then since vector object support index operation, you can use (p[0])[0] to get the first element in the vector.