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

+3


source to share


4 answers


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.

+6


source


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 type std::initializer_list<E>

or a reference to possibly cv-qualified std::initializer_list<E>

for some type E

, 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 is std::initializer_list

not predefined; if the header is <initializer_list>

not included prior to use std::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 are T

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

.

+5


source


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;

      

+1


source


You probably meant to write:

  std::vector<int> nos(N+2,0);

      

0


source







All Articles