Simple vector initialization in C ++ 11 returns weird error
Compiling this piece of code:
#include <vector>
long long sumOfMedians(int seed, int mul, int add, int N, int K)
{
std::vector<int> nos{N+2,0};
for(int i=0; i<N; i++)
{
if(i == 0)
nos[i] = seed;
else
nos[i] = (nos[i-1]*mul + add)%65536;
}
}
int main()
{
sumOfMedians(3,1,1,10,3);
return 0;
}
raises an error
*** Error in `./a.out': free(): invalid next size (fast): 0x00000000006e8010 ***
[2] 31743 abort (core dumped) ./a.out
On a slight change in the vector initialization line (line 5 in the previous code) to (line 5.6 in the new code)
#include <vector>
long long sumOfMedians(int seed, int mul, int add, int N, int K)
{
std::vector<int> nos;
nos.resize(N+2,0);
for(int i=0; i<N; i++)
{
if(i == 0)
nos[i] = seed;
else
nos[i] = (nos[i-1]*mul + add)%65536;
}
}
int main()
{
sumOfMedians(3,1,1,10,3);
return 0;
}
Makes it compile successfully. What gives?
g ++ parameter: -std = c ++ 11
source to share
For vector
, parenthesis initialization initializes the contents of the vector to the contents of the initialization list, so
std::vector<int> nos{N+2,0};
initializes it to size 2, with elements N+2
and 0
. It uses a constructor that takes a single type parameter std::initializer_list
.
Changing the parentheses to parentheses causes the two-argument constructor to be used instead, which determines the size and initial value for all elements. This is what you want here; although you can leave the second argument as default initializes to zero values.
source to share
List initialization for vectors is a way of providing a list of source elements. This is not the same as providing constructor arguments.
This is because it has an accepting constructor that works best when used : std::vector<T>
std::initializer_list<int>
{x,y,..,z}
[C++11: 8.5.4/2]:
A constructor is an initializer list constructor if its first parameter is of typestd::initializer_list<E>
or a reference to possibly cv-qualifiedstd::initializer_list<E>
for some typeE
, and either there are no other parameters, or all other parameters have default arguments (8.3.6). [Note: Initializer list constructors are preferred over other constructors in list initialization (13.3.1.7). -end note] Template isstd::initializer_list
not predefined; if the header is<initializer_list>
not included prior to usestd::initializer_list
- even an implicit use in which the type is not named (7.1.6.4) - the program is ill-formed.
[C++11: 13.3.1.7/1]:
When objects of a non-aggregate class type areT
initialized over a list (8.5.4), overload resolution selects the constructor in two phases:
- Initially, candidate functions are initializer list constructors (8.5.4) of a class
T
, and the argument list consists of an initializer list as one argument.- If no viable initializer list constructor is found, overload resolution is performed again, where all candidate functions are class constructors
T
and the argument list consists of the members of the initializer list.
So:
std::vector<int> v{1,2,3,4,5,6,7};
There are seven elements in this vector.
Similarly:
std::vector<int> nos{N+2, 0};
There are two elements in this vector; the former matters N+2
and the latter matters 0
. Your subsequent loop before N
, since it N
is 10 in your case, causes memory corruption.
If you write the following instead:
std::vector<int> nos(N+2, 0);
then you are using the expected vector constructor which works similarly std::vector::resize
.
source to share
You are initializing a size-2 vector with brace-initialization (vector has a constructor that takes std::initializer_list<int>
)
std::vector<int> nos{ N + 2, 0 };
and after that asks for index 2 ( out of range ):
nos[2] = (nos[2 - 1] * mul + add) % 65536;
source to share