Should you always initialise C++ std::vectors? - c++

I am coming from a C background where, as common practice, variables are always initialized to prevent undefined behavior. You normally, don't have any meaningful value when declaring the variables, you set the variables to 0 or {}.
I am new to C++ and I am about to code an app, which C++ classes will contain std::vectors with very long sizes... so I am just wondering if the same principles apply to std::vectors or not... and save a few loops of computational requirements
Thanks!

You will not be able to create a Vector, which is not initialized. The default constructor constructs an empty container with a default-constructed allocator.
Here are some examples on how to initialise a Vector if you already know its content or size.
// Will be an initialised empty Vector
std::vector<std::string> words;
// c++11 initializer list syntax:
std::vector<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
std::cout << "words1: " << words1 << '\n';
// words2 == words1
std::vector<std::string> words2(words1.begin(), words1.end());
std::cout << "words2: " << words2 << '\n';
// words3 == words1
std::vector<std::string> words3(words1);
std::cout << "words3: " << words3 << '\n';
// words4 is {"Mo", "Mo", "Mo", "Mo", "Mo"}
std::vector<std::string> words4(5, "Mo");
std::cout << "words4: " << words4 << '\n';

when you create a vector it gets default initialized, so it's up to you if you want to initialize it with user default values or not.
You will always get an empty vector container if you don't initialize it.
You have different ways to initialize vector to defaults like provided by #nils
but the important thing to note is std::vector encapsulates dynamic size arrays so the memory allocated to them is generally more than a static array as memory is allocated for the future growth of vector also.
Refer std::vector for more details .
and the capacity() function to understand the memory allocation to vectors .

std::vector<int> vc1(5); // number of elements
// 0 0 0 0 0
std::vector<int> vc2(5, 0); // number of elements, value of each element
// 0 0 0 0 0
That two vectors, vc1 and vc2, are same way to create new vector.

Related

How to properly iterate over QT's STL style vector

I am trying to iterate over a vector.
The vector memory is initialized to hold 10 elements max.
Now I assigned first 3 elements and try to print them using STL style iterator in QT.
#include <QDebug>
int main() {
QVector<int> vv(10);
vv[0] = 1;
vv[1] = 2;
vv[2] = 3;
QVector<int>::iterator itt;
for (itt = vv.begin(); itt != vv.end(); ++itt) {
qDebug() << vv.at(*itt);
}
}
the output is weird:
It's not 1 2 3
instead its 2 3 0 1 1 1 1 1 1 1
Why is this happening ? Can you someone explain this please.
As #NathanOliver pointed out you have two problems:
*itt already is the element of the vector, so it should just be qDebug() << *itt;.
If you create a vector of a certain size for each vector index a default element of the type the vector holds is created. That is also the reason why you can't use container classes like QVector for types without a default constructor. In your case the vector is filled with 1s on creation because 1 is the default value of an int. You then just override the first 3 values.
I have some further concerns regarding your code:
If you expect your vector to only hold as much values as you add, why even provide a length of the vector? QVector is perfectly capable of managing its storage itself. You just use QVector::append or QVector::operator<< to add values and your vector has exactly as many values as you added.
Why use STL style iterators in this case anyway? QVectorIterator provides such convenient methods to iterate over a vector. They also make the code much more readable.
If I were you I would have written the code as follows:
#include <QVector>
#include <QDebug>
int main() {
QVector<int> numbers = QVector<int>() << 1 << 2 << 3;
QVectorIterator<int> itNumbers(numbers);
while (itNumbers.hasNext()) {
qDebug() << itNumbers.next();
}
}

Why iterator is not dereferenced as an lvalue

Apologies if my question does not contain all relevant info. Please comment and I will amend accordingly.
I use CLion on Win7 with MinGW and gcc
I have been experimenting with circular buffers and came across boost::circular_buffer, but for the size of my project I want to use circular buffer by Pete Goodlife, which seems like a solid implementation in just one .hpp.
Note: I am aware of how to reduce boost dependecies thanks to Boost dependencies and bcp.
However, the following example with Pete's implementation does not behave as expected, i.e. the result to std::adjacent_difference(cbuf.begin(),cbuf.end(),df.begin()); comes out empty. I would like to understand why and possibly correct its behaviour.
Follows a MWE:
#include "circular.h"
#include <iostream>
#include <algorithm>
typedef circular_buffer<int> cbuf_type;
void print_cbuf_contents(cbuf_type &cbuf){
std::cout << "Printing cbuf size("
<<cbuf.size()<<"/"<<cbuf.capacity()<<") contents...\n";
for (size_t n = 0; n < cbuf.size(); ++n)
std::cout << " " << n << ": " << cbuf[n] << "\n";
if (!cbuf.empty()) {
std::cout << " front()=" << cbuf.front()
<< ", back()=" << cbuf.back() << "\n";
} else {
std::cout << " empty\n";
}
}
int main()
{
cbuf_type cbuf(5);
for (int n = 0; n < 3; ++n) cbuf.push_back(n);
print_cbuf_contents(cbuf);
cbuf_type df(5);
std::adjacent_difference(cbuf.begin(),cbuf.end(),df.begin());
print_cbuf_contents(df);
}
Which prints the following:
Printing cbuf size(3/5) contents...
0: 0
1: 1
2: 2
front()=0, back()=2
Printing cbuf size(0/5) contents...
empty
Unfortunately, being new to c++ I can’t figure out why the df.begin() iterator is not dereferenced as an lvalue.
I supsect the culprit is (or don't completely uderstand) the member call of the circular_buffer_iterator on line 72 in Pete's circular.h:
elem_type &operator*() { return (*buf_)[pos_]; }
Any help is very much appreciated.
The iterator you pass as the output iterator is dereferenced and treated as an lvalue, and most probably the data you expect is actually stored in the circular buffer's buffer.
The problem is, that apart from the actual storage buffer, most containers also contain some internal book-keeping state that has to be maintained. (for instance: how many elements is in the buffer, how much frees space is left etc).
Dereferencing and incrementing the container doesn't update the internal state, so the container does not "know" that new data has been added.
Consider the following code:
std::vector<int> v;
v.reserve(3);
auto i = v.begin();
*(i++) = 1; // this simply writes to memory
*(i++) = 2; // but doesn't update the internal
*(i++) = 3; // state of the vector
assert(v.size() == 0); // so the vector still "thinks" it's empty
Using push_back would work as expected:
std::vector<int> v;
v.reserve(3);
v.push_back(1); // adds to the storage AND updates internal state
v.push_back(2);
v.push_back(3);
assert(v.size() == 3); // so the vector "knows" it has 3 elements
In your case, you should use std::back_inserter, an iterator that calls "push_back" on a container every time it is dereferenced:
std::adjacent_difference(
cbuf.begin(), cbuf.end(),
std::back_inserter(df));
std::adjacent_difference writes to the result iterator. In your case, that result iterator points into df, which has a size of 0 and a capacity of 5. Those writes will be into the reserved memory of df, but will not change the size of the container, so size will still be 0, and the first 3 ints of the reserved container space will have your difference. In order to see the results, the container being written into must already have data stored in the slots being written to.
So to see the results you must put data into the circular buffer before the difference, then resize the container to the appropriate size (based in the iterator returned by adjacent_difference.

Setting vector elements in range-based for loop [duplicate]

This question already has answers here:
How can I modify values in a map using range based for loop?
(4 answers)
Closed 1 year ago.
I have come across what I consider weird behaviour with the c++11 range-based for loop when assigning to elements of a dynamically allocated std::vector. I have the following code:
int arraySize = 1000;
std::string fname = "aFileWithLoadsOfNumbers.bin";
CTdata = new std::vector<short int>(arraySize, 0);
std::ifstream dataInput(fname.c_str(), std::ios::binary);
if(dataInput.is_open()
{
std::cout << "File opened sucessfully" << std::endl;
for(auto n: *CTdata)
{
dataInput.read(reinterpret_cast<char*>(&n), sizeof(short int));
// If I do "cout << n << endl;" here, I get sensible results
}
// However, if I do something like "cout << CTdata->at(500) << endl;" here, I get 0
}
else
{
std::cerr << "Failed to open file." << std::endl;
}
If I change the loop to a more traditional for(int i=0; i<arraySize; i++) and use &CTdata->at(i) in place of &n in the read function, things do as I would expect.
What am I missing?
Change this loop statement
for(auto n: *CTdata)
to
for(auto &n : *CTdata)
that is you have to use references to elements of the vector.
you have to write
for( auto& n : *CTdata )
because auto n means short int n when you need short int& n.
i recommend you to read difference beetween decltype and auto.
The reason your loop fails is because you reference vector elements by value. However, in this case you can eliminate the loop altogether:
dataInput.read(reinterpret_cast<char*>(CTdata->data()), arraySize*sizeof(short int));
This reads the content into the vector in a single call.
Vlad's answer perfectly answers your question.
However, consider this for a moment. Instead of filling your array with zeroes from the beginning, you could call vector<>::reserve(), which pre allocates your backing buffer without changing the front facing portion of the vector.
You can then call vector<>::push_back() like normal, with no performance implications, while still maintaining the logic clear in your source code. Coming from a C# background, looping over your vector like that looks like an abomination to me, not to mention you set each element twice. Plus if at any point your element generation fails, you'll have a bunch of zeroes that weren't supposed to be there in the first place.

Segfault after repeated reallocs

EDIT: Thanks a lot for the answers. That's right, I will try using vectors instead.
I have a program where I dynamically allocate memory.
The class has an attribute which is an array of structs (**) and also an array of pointers (*) which point to each element of the array of structs, so I make 2 Mallocs. The struct is called "context".
The realloc works fine and doesn't return NULL, but as soon as I have more than 2 elements, the program will give me a segfault when trying to save a value in an element of the array. How can I prevent this segfault?
int my_class::method(uint32_t struct_element)
{
int i= this->numofcontexts;
if(this->local_context_array == NULL)
// That means it is empty and we have to make our first malloc
{
this->local_context_array = (context_t**) malloc(sizeof(context_t*));
*(this->local_context_array) = (context_t*) malloc(sizeof(context_t));
i++;
std::cout << "\n1 Malloc was made of size " << sizeof(context_t)<<"\n";
}
else
// Array is not empty and we have to use realloc
{
this->local_context_array = (context_t**) realloc(this->local_context_array, (i+1)*sizeof(context_t*));
*(this->local_context_array) = (context_t*) realloc(*(this->local_context_array), (i+1)*(sizeof(context_t)));
std::cout << "\n1 Realloc was made of size " << (i+1)*(sizeof(context_t)) <<"\n";
i++;
std::cout << "\nWe now have " << i <<" elements\n";
// As soon as the array is bigger than 2 elements, this gives segmentation fault:
//(this->local_context_array[i-1])->struct_element = struct_element;
}
From the code posted and the symptoms you describe, it seems you do not do this at the end:
this->numofcontexts = i;
If this is true, then every time you call this method, it will find numofcontexts == 0 and local_context_array not NULL, so it will move to your else clause, when it will reallocate the array to i+1 (always 1).
First call will succeed, second call will also succeed with array size of 1 element, and if you try to assign to elements over [0] at this point, you may get a segfault. The reason you might not get a segfault at [1] is usually related to some other variable occupying the space and being trashed but which does not always generate a segfault immediately.

C++ Vector push / pop

I've been looking all over for a solution to this. Not using c++11.
for(int a = 1; a < team1.chan; a++)
{
team1.nums.push_back(ppb.back());
ppb.pop_back();
cout << team1.nums[a] << " " << endl;
}
ppb is an uns int vector with 1-1000 that have been shuffled.
team1 is a struct with nums as an uns int vector.
I'm trying to take the last number in ppb and assign it to the first number in team1.nums.
Then I need to delete that value in ppb so I have no duplicates.
I printed the actual numbers in ppb and they are fine. When I compile I get about 40 numbers like 2397295 then about 80 zeroes.
I am slowly getting C++, but vectors are killing me. Thank you.
Vectors are zero indexed but your 'a' starts at 1.
So the first value from ppb.back() is stored at team1.nums[0] but you print team1.nums[1].
The next value from ppb.back() is stored at team1.nums[1] but now you print team1.nums[2].
Try to loop using
while(ppb.empty() == false)
{
...// Your code here
}
I think that all you need is
team1.nums.assign( std::make_move_iterator( team1.rbegin() ), std::make_move_iterator( team1.rend() ) );
team1.clear();
Or if the move constructor is not supported then
team1.nums.assign( team1.rbegin(), team1.rend() );
team1.clear();
It is better to use iterators when using containers. It will avoid such indexing errors. Also you have access to some neat functions like std::copy which puts all the copy code you wrote in just one line.
std::copy(ppb.rbegin(),ppb.rend(),back_inserter(team1.nums));
back_inserter uses the vector::push_back so you dont have to reserve the space