Unable to initialize size of vector along with contents - c++

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

Related

How to retrieve an array from a pointer in c++

I'm having problems with a program that only accepts arrays. I'm having plenty of pointers to different arrays, but using *p seems to only give me the first element of the array. I want to return all the elements of the array. I know the length of the array, if that helps.
#include <typeinfo>
#include <iostream>
int i[10];
int* k=i;
cout<<typeid(i).name()<<'\n';
cout<<typeid(*k).name()<<'\n';
results in 'int [10]' and 'int' respectively. I want some way of returning k as 'int [10]'.
Your k is a pointer to int. It points to the first element of the array. If you want a pointer to the whole array then you need to declare it as such.
#include <typeinfo>
#include <iostream>
int main() {
int i[10];
int* k=i;
int(*p)[10] = &i;
std::cout<<typeid(i).name()<<'\n';
std::cout<<typeid(*k).name()<<'\n';
std::cout<<typeid(*p).name()<<'\n';
}
Output:
A10_i
i
A10_i
However, as others have said, std::array is much less confusing to work with. It can do (almost) anything a c-array can do without its quirks.
Certainly there is a solution to your actual problem that does not require to get the array from a pointer to a single integer.
Example to show you how much more convenient C++ array/vector is then "C" style arrays with pointers :
#include <vector>
#include <iostream>
// with std::vector you can return arrays
// without having to think about pointers and/or new
// and your called cannot forget to call delete
std::vector<int> make_array()
{
std::vector<int> values{ 1,2,3,4,5,6 };
return values;
}
// pass by reference if you want to modify values in a function
void add_value(std::vector<int>& values, int value)
{
values.push_back(value);
}
// pass by const refence if you only need to use the values
// and the array content should not be modified.
void print(const std::vector<int>& values)
{
// use range based for loops if you can they will not go out of bounds.
for (const int value : values)
{
std::cout << value << " ";
}
}
int main()
{
auto values = make_array();
add_value(values, 1);
print(values);
std::cout << "\n";
std::cout << values.size(); // and a vector keeps track of its own size.
return 0;
}

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().

Why does my struct lose the string value even with references?

struct Word {
string wordName; //loses its value
vector<string> contents; //irrelevant for the question
int numContents = 0; //maintains its value
};
vector<Word*> wordMsgs;
int main()
{
vector<string> result;
result.push_back("wordName");
result.push_back("shouldEnterIf");
Word curr;
//New Word
if (result[1] != "") {
Word w;
w.numContents = 10; //just a testing #, suppose to represent size of vector
wordMsgs.push_back(&w);
w.wordName = result[0]; //name of Word
//here w.wordName and (*wordMsgs[0]).wordName display the same string; result[0]
curr = w;
}
//here curr.wordName displays result[0] but (*wordMsgs[0]).wordName doesn't. However, (*wordMsgs[0]).numContents returns 10 as expected
}
}
So I have a vector of struct references, assuming the push_back() method for vectors only pushes a copy to the end of the vector. I create an instance of my Word struct and put that reference into my vector, wordMsgs. I then edit the struct it is pointing too and then my string variable is lost upon leaving the if statement! However, my int variable never loses its value.
I don't understand because I used pointers (and I'm in C++ so I thought strings were a-okay) and I wouldn't think this is a local variable issue...
The variable w in:
if (...) {
Word w;
wordMsgs.push_back(&w);
...
}
Is allocated on the stack inside the scope of the if statement.
You are then adding its address to your vector of pointers.
Once outside the if statement, this variable is deallocated and the value at that address is no longer "solid", so you essentially have a "garbage address" in that vector.
From here onward, the behavior of your program is mostly unpredictable...
Here is a minimal example of what is going wrong in your code:
#include <string>
#include <vector>
#include <iostream>
int main() {
std::vector<string*> words; // why pointers?
if (true) { // scope starts here
std::string word = "muh";
words.push_back(&word); // dont do that !!
} // scope ends here
std::cout << *words.back();
}
By the time you access the string by dereferencing the pointer, the string is long gone, because word is destroyed when it goes outof scope. Dereferencing the pointer is undefined behaviour. You shouldnt have raw pointers in the vector when you dont need to. You probably wanted something like this:
#include <string>
#include <vector>
#include <iostream>
int main() {
std::vector<string> words;
if (true) {
std::string word = "muh";
words.push_back(word); // vector stores a copy ! and manages lifetime of its elements
}
std::cout << words.back();
}
You have a vector of pointers, not refrences. When you push back the adress of the locally defined struct Wors w by using &w you will lose that data directly when you go out of the if statement. You need to allocate and deallocate memory for the vector. Best to either just push objects in the vector or use a smart pointer.

C++ Create array with dynamic name

I need a create array in c++ but I need array always with variables name
int Magic(string name_array,int n)
{
string Name = "Something";
Name.append(name_array);
double * Name = new double[n];
}
int main()
{
Magic("a.txt",10);
}
And I have this error:
operator' : 'identifier1' differs in levels of indirection from 'identifier2'
I know it's not a python but maybe a map help me? How I can make this?
If you want to be able to access different arrays by string names, consider using a std::map<std::string, std::vector<double>>. This maps strings to C++'s better, more dynamic answer to arrays. In this case your code would be something like:
#include <iostream>
#include <map>
#include <vector>
void AddVector(std::map<std::string, std::vector<double>> &io_map,
const std::string& i_name,
const std::size_t i_size)
{
io_map[i_name].resize(i_size);
}
int main()
{
std::map<std::string, std::vector<double>> vector_map;
AddVector(vector_map, "Vector1", 3);
AddVector(vector_map, "Vector2", 10);
std::cout << "Vector with string key Vector1 has size: " << vector_map["Vector1"].size() << std::endl;
return 0;
}
In this code I've tried to be as close to the code you've given - resizing the vectors to the size you would have created the array in your "Magic" function. However, vectors can dynamically resize, so you may not even need to create/resize them in your code depending on your use case.

Declaration of Vectors

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.