How to randomly assign to vector in C++? - c++

I am new to C++, and am continuously told to use std::vector instead of new[].
I am trying to achieve this functionality, in where I know the size of the vector and want to assign to it randomly (not sequentially).
However, when running this, my program terminates with no error output, so I am stumped.
vector<string> v1;
v1.resize(2);
v1.insert(v1.begin() + 1, "world");
v1.insert(v1.begin() + 0, "world");
cout << v1.at(1) << endl;

Don't give up, it's easier than that
vector<string> v1(2);
v1[1] = "world";
v1[0] = "world";
cout << v1[1] << endl;
vector::insert is for when you want to add items to your vector, Not when you want to replace ones that are already there, vector::insert changes the size of the vector in other words.

First you resize it to have two empty strings:
{"", ""}
Then you insert "world" before begin() + 1 or the 2nd element:
{"", "world", ""}
Then you insert "world" before begin() or the 1st element:
{"world", "", "world, ""}
Then you access the 2nd element with v1.at(1) and get the empty string.
Presumably, you don't want std::vector::insert which inserts new elements between existing elements. You want to do this as you would with arrays, with operator[]:
vector<string> v1(2);
v1[1] = "world";
v1[0] = "world";
cout << v1.at(1) << endl;

To randomly assign
Simply use the index (obviously, validate that it's < size)
v1[index] = value;
To randomly insert (validate that index < size)
v1.insert(v1.begin() + index, value);
To sequentially insert at the end / append (no need for an index, your value will be inserted at the end of the vector)
v1.push_back(value);
If you plan on inserting many values, consider calling reserve() on your vector so that enough memory can be allocated to store all of your items, otherwise as you insert your data you may end up with many reallocation as the vector grows

Your Program is working correctly. Your error is in the logic of your code.
Insert doesn't change the string stored at index 1. It places a string at position 1, and moves all indexes after 1 to the right.
start first insert second insert
("","") -> ("", "world, "") -> ("world","","world","")
So when you print v1.at(1) you are printing an empty string.
To fix the issue, you would want to use:
v1.at(1)="world"
v1.at(0)="world"
--or--
v1[1] ="world"
v1[0] ="world"
The two solutions are equivalent, however the second will not do any bounds checking. The first will throw an error if there is an out of bounds error. This shouldn't matter as long as you can gaurantee that you will never index out of bounds.

Like many have stated, you can can just use operator[] to reassign old values, given that you've already sized the vector or filled it with other values.
If your array will always have a fixed size you can use std::array, which should provide a performance boost, at the sacrifice of the ability to resize the array or determine its size at runtime.
std::array<std::string,2> a1;
a1[0] = "world";
a1[1] = "world2";
std::cout<<a1.at(1)<<std::endl; //outputs world2
Note that the size must be static, so you can't do something like this:
int numStrings;
std::cin>>numStrings;
std::array<std::string,numStrings> a2; //ERROR
Unfortunately, I don't think there is any way of initializing an std::array without a default constructor, other than using an initialization list.
struct T
{
T(std::string s):str(s){} //no default constructor
std::string str;
}
std::array<T,2> a3 = {T(""), ""}; //you can use a conversion constructor implicitly
Obviously, this isn't practical if you want an array with a sizable number of objects.

Related

C++ vector.erase() function bug

I have this vector:
list.push_back("one");
list.push_back("two");
list.push_back("three");
I use list.erase(list.begin() + 1) to delete the "two" and it works. But when I try to output the list again:
cout<<list[0]<<endl;
cout<<list[1]<<endl;
cout<<list[2]<<endl;
produces:
one
three
three
I tried targeting the last element for erasing with list.erase(list.begin() + 2), but the duplicate three's remain. I imagined index 2 should have been shifted and list[2] should have outputted nothing. list[3] outputs nothing, as it should.
I'm trying to erase the "two" and output the list as only:
one
three
When using cout<<list[2]<<endl; you asume that you still have three elements. But in fact you are accessing remaining data in a part of the memory that is no more used.
You should use list.size () to obtain the number of elements. So, something like:
for ( size_t i = 0; i < list.size (); i++ )
{
cout<<list[i]<<endl;
}
But you erased the element, thus the size of your container was decreased by one, i.e. from 3 to 2.
So, after the erase, you shouldn't do this:
cout<<list[0]<<endl;
cout<<list[1]<<endl;
cout<<list[2]<<endl; // Undefined Behaviour!!
but this:
cout<<list[0]<<endl;
cout<<list[1]<<endl;
In your case, the "three" is just copied to the index 1, which is expected. you is vector.size() == 2 now.
it is because vector will do pre-allocation, which help to improve the performance.
To keep from having to resize with every change, vector grabs a block of memory bigger than it needs and keeps it until forced to get bigger or instructed to get smaller.
To brutally simplify, think of it as
string * array = new string[100];
int capacity = 100
int size = 0;
In this case you can write all through that 100 element array without the program crashing because it is good and valid memory, but only values beneath size have been initialized and are meaningful. What happens when you read above size is undefined. Because reading out of bounds is a bad idea and preventing it has a performance cost that should not be paid by correct usage, the C++ standard didn't waste any time defining what the penalty for doing so is. Some debug or security critical versions will test and throw exceptions or mark unused portions with a canary value to assist in detecting faults, but most implementations are aiming for maximum speed and do nothing.
Now you push_back "one", "two", and "three". The array is still 100 elements, capacity is still 100, but size is now 3.
You erase array[1] and every element after 1 up to size will be copied up one element (note potentially huge performance cost here. vector is not the right data structure choice if you are adding and removing items from it at random locations) and size will be reduced by one resulting in "one", "three", and "three". The array is still 100 elements, capacity is still 100, but size is now 2.
Say you add another 99 strings. This pushes size each time a string is added and when size will exceed capacity, a new array will be made, the old array will be copied to the new, and the old will be freed. Something along the lines of:
capacity *= 1.5;
string * temp = new string[capacity];
for (int index = 0; index < size; index ++)
{
temp[index] = array[index];
}
delete array;
array = temp;
The array is now 150 elements, capacity is now 150, and size is now 101.
Result:
There is usually a bit of fluff around the end of a vector that will allow reading out of bounds without the program crashing, but do not confuse this with the program working.

std::out_of_range basic_string when going to the next element from an empty string in vector

I have a std::vector<std::string> that holds separate strings at each index. Each row represents a new string and each column represents the (index + 1) of a character in the string.
If I insert an empty string in a specific row (starting at 1), by doing:
lines.insert(lines.begin() + row, "");
row++;
column = 1;
This means if I inserted the empty string at row 2, my vector looks like this:
{ "Hello", "", "World" }
But, if I move from row 1 ("Hello"), to row 2 (""), by doing
row++;
column = 1;
I get the error:
terminating with uncaught exception of type std::out_of_range: basic_string
The same error happens if I move from row 2 to row 3, so moving to a row with a valid column doesn't work.
This error doesn't happen if I don't have an empty string though. If I have anything put into the new string that is then inserted into the vector, I can use row++; without error.
I believe I have the answer to your problem. Upon closely reading your post, it seems that you are inserting into positions 1, 2, and 3 of the vector.
A vector works like an array. I won't go into details of the implementation of the vector but what you need to take note of is that arrays start from index 0.
Now, you also need to understand how vector.begin() and vector.end() works. vector.begin() works like a pointer that points to the first element of the vector. vector.end() works like a pointer that points to one after the last element of the vector.
Since row starts from 1, what you're doing is inserting into *one after the first element of your vector when you perform lines.insert(lines.begin() + row, ""). Therefore, your vector becomes like this:
{ <uninitialized string>, "Hello", "", "World" }
Thank you for reading.

Use Object in vector in loop

Currently, i have a loop iterating through a vector, and i'm trying to find the index of an object, while i'm in the loop, to delete it. How can i go about this?
Here's my code :
for (Object &a : objectDict)
{
a.setTime(theTime);
double tempMoveX = 0, tempMoveZ = 0, tempUX = 0,tempUZ = 0;
for (Object &b : objectDict)
{
if (a != b)
{
...
debug << fixed << setprecision(20) << "Collision" << endl;
a.appendMass(b.getMass());
objectDict.erase(find(objectDict.begin(), objectDict.end(), b));
...
Thats the important part. How can i erase object b from the vector?
One easy way is to simply build a separate vector containing the indexes of elements to erase later. Once you've finished going through the regular vector, loop in reverse order through the "to be removed" vector (in reverse because you don't want to invalidate the indexes as you go), and erase them.
Alternatively, as you iterate over the original vector, select the elements you want to keep, and copy them to another vector. At the very end, swap the two vectors (which is cheap). This will work better if you have relatively many elements to delete, on average.
Well, in case you need an index while iterating vector's elements, instead of:
for (Object &a : objectDict) { ...
do traditional:
for (size_t i = 0; i < objectDict.size(); ++i) { ...
and within the loop's body: instead of using reference a, you'll use objectDict[i], then when you will need to erase element, you can do:
objectDict.erase(vec.begin() + i);
i--;
i-- is used to move the index backwards by 1 so that when the next iteration increments it again, the element that follows right after the element that has been erased is not skipped.

vector constructor creating vector with one less element

I am trying to split a vector into "almost equal" parts, and create subvectors for those parts.
I have asked the original question here: How to split a vector into n "almost equal" parts but I found a really good solution, what I am trying to use, from here: Best way to extract a subvector from a vector?
I wrote this function for creating integers for start and end values (round is my function which rounds to specified digits.)
void split( double number, double parts )
{
double loop = number / parts;
for( int i = 0; i < parts; i++ )
{
int start = round( i * loop, 0 );
int end = round( ( i + 1 ) * loop - 1, 0 );
cout << start << " " << end << endl;
}
}
This function so far works OK, but my problem is that when I try to run this:
vector<some> dest( &source[start], &source[end] );
Then it creates one LESS element, then required. I mean for example if I call it with
vector<some> dest( &source[0], &source[99] );
then it will have 99 elements, instead of 100. Why is this happening?
How can I fix it? If I use [end+1], then it terminates at the last vector, with "subscript out of range."
The vector constructor (and all STL constructors that accept pointer ranges, for that matter) are designed to take in a range of STL-style iterators. When using iterators, you specify a range by providing a pointer to the first- and the past-the-end elements, not the first and last elements. If you wanted to create a vector as a copy of the subrange (0, 99) out of another vector, you could write
vector<some> dest(source.begin(), source.begin() + 100);
Note that this uses vector iterators to specify the slice of the first 100 elements rather than operator[], which has undefined behavior when the provided index is out of bounds. In your case, this undefined behavior is manifesting as a runtime debug error. Iterators don't have this problem, since they're specifically designed to be used this way.
If you want to use raw C++ arrays as input to the vector constructor, you could do it like this:
vector<some> dest(source, source + 100);
Hope this helps!
While it's not legal to use &v[n] if v is an std::vector with n elements you can use instead
vector<some> dest(v.begin()+first, v.begin()+last+1);
even if last+1 == n.

Adding to middle of std::vector

Is there a way to add values to the middle of a vector in C++? Say I have:
vector <string> a;
// a gets filled up with "abcd", "wertyu", "dvcea", "eafdefef", "aeefr", etc
and I want to break up one of the strings and put all of the pieces back into the vector. How would I do that? the strings I break can be anywhere, index = 0, somewhere in the middle, or index = a.size() - 1.
You can insert into a vector at position i by writing
v.insert(v.begin() + i, valueToInsert);
However, this isn't very efficient; it runs in time proportional to the number of elements after the element being inserted. If you're planning on splitting up the strings and adding them back in, you are much better off using a std::list, which supports O(1) insertion and deletion everywhere.
You can do that, but it will be really slow:
int split = 3; // where to split
a.insert(a.begin()+index, a[index].substr(0, split));
a[index+1] = a[index+1].substr(split);
in this example dynamically find the vector middle and insert new element.
std::vector <std::string> friends;
friends.push_back("Ali");
friends.push_back("Kemal");
friends.push_back("Akin");
friends.push_back("Veli");
friends.push_back("Hakan");
// finding middle using size() / 2
int middleIndexRef = friends.size() / 2;
friends.insert(friends.begin() + middleIndexRef, "Bob");