Declaration of Vectors - c++

Vectors size dynamically, so why is this giving a seg fault:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
vector<int> vectorOfInts;
vectorOfInts[0] = 3;
}
What I'm trying to actually do is declare a vector in a class.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Directory{
public:
string name;
int maxIndex;
vector<Directory> subDirectories;
void addSubdirectory(string x){
Directory newSubdirectory(x);
subDirectories[maxIndex++] = newSubdirectory;
}
Directory(string x){
name = x;
maxIndex = 0;
}
};
int main(){
Directory root("root");
root.addSubdirectory("games");
}
But this also gives a seg fault.

Vectors don't resize entirely automatically. You use push_back or resize to change the size of a vector at run-time, but the vector will not automatically resize itself based on the index you use--if you index beyond its current size, you get undefined behavior.
In your demo code, you could do something like this:
vector<int> vectorOfInts(1);
vectorOfInts[0] = 3;
Alternatively, since you're just adding 3 to the end of the existing data (or nonexistent data, in this case) you could just use push_back (or emplace_back):
vector<int> vectorOfInts;
vectorOfInts.push_back(3);
It looks like the same basic approach will work with your real code as well. It also simplifies things a bit, since you don't need to explicitly track the maxIndex as you've done.

A default-constructed vector has no elements (i.e. its size() returns zero).
The operator[] does not check if it is supplied a valid index, and gives undefined behaviour if supplied an invalid index. It does not resize the vector. A vector with size zero has no valid indices.
That combination explains your problem.

The seg fault, come from the fact that you try to acces an element that does not exist. When you use operator [ ], be sure that you already alocate memory for this element using resize, push_back, emplace_back...
To make your code work, just replace this
void
addSubdirectory(string x)
{
Directory newSubdirectory(x);
subDirectories[maxIndex++] = newSubdirectory;
}
by
void
addSubdirectory(string x)
{
subDirectories.emplace_back(x); // c++11
// else subDirectories.push_back(Directory(x));
}
and you don't need the maxIndex, you can have it using the size method: subDirectories.size() - 1.

Related

Nested container in c++

I am new to C++ concepts,I am very much confused in inserting a value in a nested container.
#include<bits/stdc++.h>
using namespace std;
int main()
{
vector<vector<vector<vector<vector<int>>>>>s;
s[0][0][0][0].push_back(5);
return 0;
}
My program gets terminated abnormally.
You've default initialised s. The default constructor of vector creates an empty vector.
s[0] accesses the first element of the vector. An empty vector has no elements. This is a contradiction. The behaviour of accessing elements outside the bounds of the vector is undefined.
You could initialise a non-empty vector for example like this:
std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> s
{ // std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>>
{ // std::vector<std::vector<std::vector<std::vector<int>>>>
{ // std::vector<std::vector<std::vector<int>>>
{ // std::vector<std::vector<int>>
{5}, // std::vector<int>
},
},
},
};
You have to insert elements to each vectors before accesing. Otherwise, you will wrongly access to a nonexistent element.
#include <vector>
using std::vector;
int main()
{
vector<vector<vector<vector<vector<int>>>>>s;
s.push_back(vector<vector<vector<vector<int>>>>());
s[0].push_back(vector<vector<vector<int>>>());
s[0][0].push_back(vector<vector<int>>());
s[0][0][0].push_back(vector<int>());
s[0][0][0][0].push_back(5);
return 0;
}
Either stick with vector and follow eerorika's suggestion or choose a container default-constructing elements upon access, like std::map:
#include <map> // don't use stdc++.h or using namespace std
int main()
{
template<class T>
using map = std::map<std::size_t, T>;
map<map<map<map<map<int>>>>> s;
s[0][0][0][0][0] = 5;
}

What is the structure of a std::vector?

I have made a recursive way of printing all of the elements of a vector, but it returns nonsense! and it throws a really strange exception:
Exception thrown: read access violation.
std::vector<int,std::allocator<int> >::operator[](...) returned nullptr.
And it outputs: 12358000
This is the code. What is the mistake I have made?
#include <iostream>
#include <vector>
using namespace std;
int printVec(vector<int>* foo) {
if ((*foo).empty())
return 0;
else {
cout << (*foo)[0];
printVec(foo + 4);
}
}
int main() {
vector<int> ref{ 1,2,3,4,5,6,7,8,9,0 };
printVec(&ref);
}
foo is a pointer to a std::vector<int>.
foo + 4 is adding 4 lots of sizeof(std::vector<int>) to foo in pointer arithmetic. There is not a std::vector at that location, so the behaviour of printVec(foo + 4) is undefined.
The expression (*foo)[0] is calling the overloaded [] operator on a std::vector which access the first element in the vector. If there is no element at that position then the behaviour of the program is undefined.
What is the mistake I have made?
You are using a pointer to a single vector and treat it as if it points into an array of std::vector<int>. It is only allowed to increment pointers that point to elements in arrays (actually you are allowed to get a pointer one past an object, but not more). A single std::vector is not an array and your code invokes undefined behavior by incrementing foo here: printVec(foo + 4);.
If you want to "point to" elements of the vector use iterators:
#include <iostream>
#include <vector>
using namespace std;
template <typename IT>
void printVec(IT current, IT end) {
if (current == end) return;
else {
cout << *current;
printVec(current+1,end);
}
}
int main() {
vector<int> ref{ 1,2,3,4,5,6,7,8,9,0 };
printVec(ref.begin(),ref.end());
}
What is the structure of a std::vector?
You need not know nor care. If you want to iterate elements use iterators. If you want to access the underlying array use .data().

is there any way to define dynamic array without Determine the size of it

I need a dynamic array that I don't have to scale(Determine) to a fixed number like the following
string* s;
I have this code so far, but obviously it doesn't work.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
fstream f;
f.open("resa.txt");
string* s;
int i = 0;
while (f.good())
{
f >> *(s + i);
i++;
}
return 0;
}
This is my task:
Now we change the class definitions a bit. No static arrays can occur anymore. The fact that the arrays instead become dynamic means that some class methods need to be modified, and that some / some of the classes need copy constructors and assignment methods (or superimposed assignment operator). [...]"
This means, that I just can't use data structures.
It's not automatic, you have to allocate more memory every time you want to resize, copy elements into new array and delete the old one. Fortunately, standard library got you covered with std::vector - an automatically resizable array.
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
fstream f;
f.open("resa.txt");
string temp;
std::vector<std::string> s;
while (f >> temp)
{
s.push_back(temp);
}
return 0;
}
I also fixed your input reading - see Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong? (applies to good() as well).
Alternatively, you can use std::istream_iterator to initialize vector in one line instead of using loop (credit to Ayxan):
vector<string> s{ istream_iterator<string>{f}, {} };

Unable to initialize size of vector along with contents

The code below is just the isolated problem. I want to not only reserve the size of the vector but also initialize the contents so that if a vector element within the size range is suddenly assigned a value, it won't throw a vector subscript out of range error. I'm basically replacing a fixed-size array that is used throughout a large amount of code and I want the same functionality without having to add "item.push_back(newItem)" to throughout the file. I tried putting a for loop inside the Node constructor that just added but for some reason the .push_back() method was unrecognized.
How would I not only reserve the size, but also initialize the contents within the constructor?
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
int maxSize = 3;
struct Item{
string key;
string value;
};
struct Node{
int count;
vector<Item> items;
Node()
{
items.reserve(maxSize + 1);
}
};
int main(int argc, char *argv[])
{
Item item;
item.key = "Hi";
item.value = "there";
Node *p = new Node();
p->items[1] = item; // Error: vector subscript out of range
cout << p->items[1].key << " " << p->items[1].value << endl;
return 0;
}
Reserving only allocates underlying memory, for purposes of optimisation. If you don't know you need it, you don't. If you don't know you need it, and you wrote it, you shouldn't have done.
What you're trying to do is make the vector actually take on a size, and fill up with elements that you can immediately access via operator[].
To do so, write resize instead of reserve.
In fact, since you're doing so on a member in the constructor of its container, what you really should be doing is initialising the vector by calling its proper constructor:
struct Node
{
int count;
vector<Item> items;
Node()
: items(maxSize + 1)
{}
};
You're looking for resize instead of reserve

cannot access the vector members of a class

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.