1

We can initialize a valarray from a basic user defined array as following:

int arr[3]={0};
valarray<int> test(arr, sizeof(arr)/sizeof(int));

How can we move the other way around? Suppose we have a valarray<int> and we need to convert back to a basic user defined array? I didn't find anything in the documentation.

mibrahimy
  • 722
  • 4
  • 18

3 Answers3

3

You can't create an array from a valarray without using dynamic memory since the size of a valarray object is not known at compile time.

std::valarray<int> test{10, 20};
int arr[test.size()];  // Not standard C++. Some compilers support this
                       // as an extension.

// This is how you can get a dynamic array from a valarray.
int* arr = new int[test.size()];
std::copy(begin(test), end(test), arr);

It will be better to use std::vector<int> instead of trying to manage dynamically allocated memory in application code.

std::vector<int> arr(begin(test), end(test));
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Isn't the complexity of the `std::copy` same as that of a loop? – mibrahimy Dec 21 '17 at 16:42
  • @IbrahimYousaf, yes, it is. – R Sahu Dec 21 '17 at 16:47
  • 2
    @IbrahimYousaf: In practice, it may often be faster. See http://en.cppreference.com/w/cpp/algorithm/copy, which says: *"In practice, implementations of std::copy avoid multiple assignments and use bulk copy functions such as std::memmove if the value type is TriviallyCopyable."* – Christian Hackl Dec 21 '17 at 17:02
2

How can we move the other way around?

If you know the valarray's size at compile time, then you can prepare an int[3] and copy the values to the individual elements, e.g. using std::copy:

#include <valarray>
#include <algorithm>
#include <iostream>

int main()
{
    std::valarray<int> va { 1, 2, 3 };
    int arr[3] = { 0 };
    std::copy(begin(va), end(va), arr);

    std::cout << arr[0] << '\n';
    std::cout << arr[1] << '\n';
    std::cout << arr[2] << '\n';
}

You could even initialise the array with the correct values right away:

#include <valarray>
#include <iostream>

int main()
{
    std::valarray<int> va { 1, 2, 3 };
    int arr[] = { va[0], va[1], va[2] };

    std::cout << arr[0] << '\n';
    std::cout << arr[1] << '\n';
    std::cout << arr[2] << '\n';
}

If the size isn't known at compile time, then use std::vector instead:

#include <valarray>
#include <vector>
#include <iostream>

int main()
{
    std::valarray<int> va { 1, 2, 3 };
    std::vector<int> v(begin(va), end(va));

    for (auto const& element : v)
    {
      std::cout << element << '\n';
    }
}
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • If my array size is huge, and complexity of the `std::copy` is linear. What would be an optimized way? – mibrahimy Dec 21 '17 at 16:45
  • 1
    @IbrahimYousaf: You have to measure to find out. Perhaps you should look for alternative ways: (1) try to get rid of the `std::valarray` completely in favour of `std::vector`, (2) try to refactor the rest of the code to use iterator pairs, so that you can continue to use `std::valarray`'s `begin` and `end` specialisations, at least if you can use C++17. It really depends on what you intend to do with the valarray's contents... – Christian Hackl Dec 21 '17 at 16:51
  • 1
    @IbrahimYousaf Constructing the `valarray` from the array is also linear time. – Daniel H Dec 21 '17 at 16:59
0

As long as the size of the valarray does not change, you can use the address of the first element as the start of basic array.

#include <valarray>
#include <iostream>

int main() {
  int a[] = {1, 2, 3};
  std::valarray va(a, 3);
  std::cout << a[0] << ',' << a[1] << ',' << a[2] << '\n';
  std::cout << va[0] << ',' << va[1] << ',' << va[2] << '\n';
  int *b = &va[0];
  std::cout << b[0] << ',' << b[1] << ',' << b[2] << '\n';
}
sercxjo
  • 328
  • 2
  • 12