Is it possible to get a sparse (non-contiguous) subset of references to array elements?
Suppose I have array a = [1,4,5] and indices pos = [0,1]. I would like to get b = [1,5] without copying elements from a. In other words, I would like to slice into a and create a view called b.
The following errors since "expression is not assignable":
#include <array>
int main() {
std::array<double,3> a = {1, 4, 5};
std::array<double, 2> b;
int c = 0;
int pos[2] = {0,2};
for (auto i = a.begin(); i != a.end(); i++) {
&b[c] = i;
i++;
}
return 0;
}
You can't have direct references in a container. However, if you have access to C++11 you can use std::reference_wrapper:
#include <iostream>
#include <functional>
#include <vector>
#include <array>
int main() {
std::array<double,3> a = {1, 4, 5};
std::vector<std::reference_wrapper<double>> b;
int pos[2] = {0,2};
for (unsigned int i = 0; i < sizeof(pos) / sizeof(pos[0]); ++i)
{
b.emplace_back(a[pos[i]]);
}
for(const auto& viewer: b)
{
std::cout << viewer << "\n";
}
}
Otherwise, just use double*.
C++ Standard 8.3.2/4:
There shall be no references to references, no arrays of references,
and no pointers to references.
Answered here
However you can have a container array of a class with a referance member (initlized on constractor) and implement a =operator, if it's worth the effort
Related
This question already has answers here:
Correct way to work with vector of arrays
(4 answers)
Closed 2 years ago.
This doesn't compile:
vector<int[2]> v;
int p[2] = {1, 2};
v.push_back(p); //< compile error here
https://godbolt.org/z/Kabq8Y
What's the alternative? I don't want to use std::array.
The std::vector declaration on itself compiles. It's the push_back that doesn't compile.
You could use a structure containing an array, or a structure containing two integers, if you really don't want to use std::array:
struct coords {
int x, y;
};
vector<coords> v;
coords c = {1, 2};
v.push_back(c);
alternatively, as mentioned, you could use a structure containing an array:
struct coords {
int x[2];
};
vector<coords> v;
coords c = {1, 2};
v.push_back(c);
Use std::array:
vector<std::array<int, 2>> v;
std::array<int, 2> p = {1, 2};
v.push_back(p);
I think you should check the C++ reference for vectors.
http://www.cplusplus.com/reference/vector/vector/vector/
You can see in the example, there is explained every way you can initialize a vector.
I think that for your case you need to do:
std::vector<int> v({ 1, 2 });
v.push_back(3);
As an alternative, as you explicitly state that std::array is not to be used, you could use pointers, it's kind of an oddball solution but it would work:
#include <iostream>
#include <vector>
int main()
{
const int SIZE = 2;
std::vector<int*> v;
static int p[SIZE] = {1, 2}; //extended lifetime, static storage duration
int *ptr[SIZE]; //array of pointers, one for each member of the array
for(int i = 0; i < SIZE; i++){
ptr[i] = &p[i]; //assign pointers
}
v.push_back(*ptr); //insert pointer to the beginning of ptr
for(auto& n : v){
for(int i = 0; i < SIZE; i++){
std::cout << n[i] << " "; //output: 1 2
}
}
}
I want to achieve more less the equivalent to this Python code in C++ (but more memory efficient):
a = [1, 5, 3]
additional = 6
for elem in [additional] + a:
print(elem) # prints: 6 1 5 3
# alternative without creating the additional vector:
import itertools
for elem in itertools.chain([additional], a):
print(elem)
The only way that I know to do this in C++ is:
#include <iostream>
#include <vector>
int main() {
std::vector<int> a = {1, 5, 3};
int additional = 6;
for (int i = 0; i < a.size() + 1; ++i) {
int cur_elem;
if (i == 0) {
cur_elem = additional;
} else {
cur_elem = a[i-1];
}
std::cout << cur_elem << std::endl;
}
}
Is there a way to do this with a range based for loop? I found the Boost join operator but it seems to use only iterables, so I need to create an extra vector (like in the Python example).
Ideally, the iteration would be without creating the joined object in the memory and with algorithms of the standard library.
It can be done using the upcoming ranges feature.
Here's an example using Eric Niebler's range-v3 library:
#include <iostream>
#include <vector>
#include <range/v3/view/concat.hpp>
#include <range/v3/view/single.hpp>
int main() {
std::vector<int> a = {1, 5, 3};
int additional = 6;
for (auto i : ranges::concat_view(ranges::single_view{additional}, a)) {
std::cout << i;
}
}
See it live!
by using views, all iterator operations are lazy, and no extra memory is used (e.g.: no extra vectors/arrays are created)
Or, without the for loop:
ranges::copy(ranges::concat_view(ranges::single_view{additional}, a), ranges::make_ostream_joiner(std::cout, ","));
See it live!
(Honestly, I like the for version better, though)
Standard-compliant solution
There's a small issue with the solution above: concat_view did not make it into C++20. If you want a strictly compliant solution, you may want to create your own version, or use join_view instead:
#include <iostream>
#include <vector>
#include <ranges>
int main() {
std::vector<int> a = {1, 5, 3};
int additional = 6;
std::vector v{{additional}, a};
for(int i : std::ranges::join_view{v}) {
std::cout << i;
}
}
Write a function which will take two arrays as parameters and add the individual
elements of each array together such that firstArray[i] = firstArray[i] +
secondArray[i] where 0 <= i <= 4.
int[] sumEqualLengthArrays(int[] a, int[] b) {
int[] result = new int[a.length];
for (int i = 0; i < a.length; i++)
result[i] = a[i] + b[i];
return result;
}
I have been stuck on this for a while now and I just can't get my head around what the answer is. I have attempted to answer it in the code above. I am a beginner to C++ programming as I am studying it in my free time. An answer to this question would really help!
Since you said you can use anything, Use std::vector with std::transform and std::plus<int>(). something like this :
std::transform (a.begin(), a.end(), b.begin(), a.begin(), std::plus<int>());
If you insist on using normal arrays (here assume a and b are arrays) then you can do something like this :
std::transform(a, &a[number_of_elements], b, a, std::plus<int>());
But please, don't.. Use std::vector.
How to use first approach :
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {1, 2, 3};
std::transform(a.begin(), a.end(), b.begin(), a.begin(), std::plus<int>());
for(auto iter = a.begin(); iter != a.end(); ++iter)
{
std::cout << *iter << std::endl;
}
return 0;
}
How to use second approach :
#include <iostream>
#include <algorithm>
int main()
{
int a[3] = {1, 2, 3};
int b[3] = {1, 2, 3};
std::transform(a, &a[0] + 3, b, a, std::plus<int>());
for(int i = 0; i < 3; ++i)
{
std::cout << a[i] << std::endl;
}
return 0;
}
Something like this:
std::vector<int> sumEqualLengthArrays(const std::vector& rhs,
const std::vector& lhs){
if(lhs.length() == rhs.length()){
std::vector<int> result(rhs.length(), 0);
for(unsigned int i = 0; i < rhs.length; ++i){
result[i] = rhs[i] + lhs[i];
}
return result;
}else{
std::cout << "Length is not equal!" << std::endl;
return rhs;
}
}
I would advise to use vectors instead of arrays and check the length before usage just in case to avoid errors.
You've written the summing expression already in the problem formulation. If you look at it once again, you'll see that the result is stored in first and there's no need in separate result array (returning an array is not a trivial thing in C++).
And, speaking of which, passing arrays as arguments is not easy either.
Assuming, you don't use std::vector, simple options are as follows.
int a[] (note the position of square brackets) as a function formal argument is synonymous to a pointer. It does not contain any size information, so you'll have to add a third argument which is the minimal size of both arrays:
int *add(int a[], int b[], std::size_t commonSize) { // commonSize is the least of a's and b's sizes
for(std::size_t i = 0; i < commonSize; ++i) a[i] += b[i];
return a;
}
You can deduce array's size when passed by reference, this is allowed in C++ and is a serious deviation from classic C:
template<std::size_t A, std::size_t B> int (&add(int (&a)[A], int (&b)[B]))[A] {
for(std::size_t i = 0; i < std::min(A, B); ++i) a[i] += b[i];
return a;
}
Then the common size is the minimum of A and B.
You can use std::array, this is almost the same as previous option
template<std::size_t A, std::size_t B> void add(std::array<int, A> &a, std::array<int, B> const &b);
This way you can even use range-for loops, or, for instance, STL algorithms (which tend to acquire parallelized and non-sequential overloads recently), though it requires a small amount of additional work (which is a bit too large to fit in this margin).
I am defining a dynamic array in c++:
double *values;
int size = 5;
values = new (nothrow) double[size];
I know this works because it compiles, but I see some potential problems.
Say I want to assign values to this array:
double samples = [1,2,3,4,5,6];
values = samples; //runtime error: free or corruption
What exactly is happening to generate this error?
You should use std::copy to copy a static array to a dynamic array like the example below:
#include <iostream>
#include <algorithm>
int main() {
int *a = new int[5];
int b[] = {1, 2, 3, 4, 5};
std::copy(b, b + 5, a);
for(std::size_t i(0); i < 5; ++i) std::cout << a[i] << " ";
std::cout << std::endl;
return 0;
}
LIVE DEMO
Alternatively if you want the convenience of assignments instead of element-wise copying and provided that you know the size of the arrays in compile time and your compiler supports C++11 features, use std::arrays like the example below:
#include <iostream>
#include <array>
int main() {
std::array<int, 5> a;
std::array<int, 5> b {{1, 2, 3, 4, 5}};
a = b;
for(auto i : a) std::cout << i << " ";
std::cout << std::endl;
return 0;
}
LIVE DEMO
However, it is recommend to prefer std::vector over the use of raw dynamic arrays like the example below:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> a(5);
int b[] = {1, 2, 3, 4, 5};
std::copy(b, b + 5, a.begin());
for(auto i : a) std::cout << i << " ";
std::cout << std::endl;
return 0;
}
LIVE DEMO
It doesn't work because you're assigning a static array to a pointer.
double *values;
double samples[] = {1,2,3,4,5,6};
They're two different data types as far as the compiler is concerned.
When you say:
values = new double[size];
You're creating a block of heap (dynamic) memory, and "values" holds the memory address of the first element in the array. To fill in the values from your static array, you need to assign each element individually like so:
values[0] = samples[0];
values[1] = samples[1];
// or better yet
for (int i = 0; i < size; i++)
values[i] = samples[i]
You can use a std::vector which has an iterator constructor, this will solve the problem for you.
std::vector<double> values(std::begin(samples), std::end(samples));
This will ensure the heap memory is properly cleaned up, even in the case of exception, and employs the implementation's debugging machinery to help protect you from events like buffer overflow.
How do I iterate through a list of numbers, and how many different ways are there to do it?
What I thought would work:
#include <cstdlib>
#include <iostream>
#include <list>
using namespace std;
int main()
{
int numbers[] = {2, 4, 6, 8};
int i = 0;
for(i=0; i< numbers.size();i++)
cout << "the current number is " << numbers[i];
system("pause");
return 0;
}
I get an error on the for loop line:
request for member 'size' in 'numbers', which is of non-class type 'int[4]'
Unlike a lot of modern languages plain C++ arrays don't have a .size() function. You have a number of options to iterate through a list depending on the storage type.
Some common options for storage include:
// used for fixed size storage. Requires #include <array>
std::array<type, size> collection;
// used for dynamic sized storage. Requires #include <vector>
std::vector<type> collection;
// Dynamic storage. In general: slower iteration, faster insert
// Requires #include <list>
std::list<type> collection;
// Old style C arrays
int myarray[size];
Your options for iteration will depend on the type you're using. If you're using a plain old C array you can either store the size somewhere else or calculate the size of the array based on the size of it's types. Calculating the size of an array has a number of drawbacks outlined in this answer by DevSolar
// Store the value as a constant
int oldschool[10];
for(int i = 0; i < 10; ++i) {
oldschool[i]; // Get
oldschool[i] = 5; // Set
}
// Calculate the size of the array
int size = sizeof(oldschool)/sizeof(int);
for(int i = 0; i < size; ++i) {
oldschool[i]; // Get
oldschool[i] = 5; // Set
}
If you're using any type that provides a .begin() and .end() function you can use those to get an iterator which is considered good style in C++ compared to index based iteration:
// Could also be an array, list, or anything with begin()/end()
std::vector<int> newschool;
// Regular iterator, non-C++11
for(std::vector<int>::iterator num = newschool.begin(); num != newschool.end(); ++num) {
int current = *num; // * gets the number out of the iterator
*num = 5; // Sets the number.
}
// Better syntax, use auto! automatically gets the right iterator type (C++11)
for(auto num = newschool.begin(); num != newschool.end(); ++num) {
int current = *num; // As above
*num = 5;
}
// std::for_each also available
std::for_each(newschool.begin(), newschool.end(), function_taking_int);
// std::for_each with lambdas (C++11)
std::for_each(newschool.begin(), newschool.end(), [](int i) {
// Just use i, can't modify though.
});
Vectors are also special because they are designed to be drop-in replacements for arrays. You can iterate over a vector exactly how you would over an array with a .size() function. However this is considered bad practice in C++ and you should prefer to use iterators where possible:
std::vector<int> badpractice;
for(int i = 0; i < badpractice.size(); ++i) {
badpractice[i]; // Get
badpractice[i] = 5; // Set
}
C++11 (the new standard) also brings the new and fancy range based for that should work on any type that provides a .begin() and .end(). However: Compiler support can vary for this feature. You can also use begin(type) and end(type) as an alternative.
std::array<int, 10> fancy;
for(int i : fancy) {
// Just use i, can't modify though.
}
// begin/end requires #include <iterator> also included in most container headers.
for(auto num = std::begin(fancy); num != std::end(fancy); ++num) {
int current = *num; // Get
*num = 131; // Set
}
std::begin also has another interesting property: it works on raw arrays. This means you can use the same iteration semantics between arrays and non-arrays (you should still prefer standard types over raw arrays):
int raw[10];
for(auto num = std::begin(raw); num != std::end(raw); ++num) {
int current = *num; // Get
*num = 131; // Set
}
You also need to be careful if you want to delete items from a collection while in a loop because calling container.erase() makes all existing iterators invalid:
std::vector<int> numbers;
for(auto num = numbers.begin(); num != numbers.end(); /* Intentionally empty */) {
...
if(someDeleteCondition) {
num = numbers.erase(num);
} else {
// No deletition, no problem
++num;
}
}
This list is far from comprehensive but as you can see there's a lot of ways of iterating over a collection. In general prefer iterators unless you have a good reason to do otherwise.
Change you for loop to
for(i=0; i< sizeof(numbers)/sizeof(int);i++){
In simple words,
sizeof(numbers) mean number of elements in your array * size of primitive type int, so you divide by sizeof(int) to get the number of elements
If you fix it so that it's list<int> numbers = {1,2,3,4}:
Iterating through using iterators:
#include <iterator>
for(auto it = std::begin(numbers); it != std::end(numbers); ++it) { ... }
Iterating through using std::for_each:
#include <algorithm>
#include <iterator>
std::for_each(numbers.begin(), numbers.end(), some_func);
Utilizing a for-each loop (C++11):
for(int i : numbers) { ... }
I didn't see it among the answers but this is imo the best way to do it: Range-based for loop
It is safe, and in fact, preferable in generic code, to use deduction to forwarding reference:
for (auto&& var : sequence).
Minimalist and working example :
#include <list>
#include <iostream>
int main()
{
std::list<int> numbers = {2, 4, 6, 8};
for (const int & num : numbers)
std::cout << num << " ";
std::cout << '\n';
return 0;
}
If your list of numbers is fixed be aware that you can simply write:
#include <iostream>
#include <initializer_list>
int main()
{
for (int i : {2, 4, 6, 8})
std::cout << i << std::endl;
return 0;
}
There is no size function on "plain" C-style arrays. You need to use std::vector if you want to use size, or calculate size through sizeof.
In C++11 you can use array initialization syntax to initialize your vectors, like this:
vector<int> numbers = {2, 4, 6, 8};
Everything else stays the same (see demo here).
You can also use the plain old C containers and use the iterator syntax for the loop:
#include <iostream>
int main()
{
int numbers[] = {2, 4, 6, 8};
int *numbers_end = numbers + sizeof(numbers)/sizeof(numbers[0]);
for (int *it = numbers; it != numbers_end; ++it)
std::cout << "the current number is " << *it << std::endl;
return 0;
}
There is no member function "size" because "numbers" isn't a class. You can not get the array's size this way, you must either know it (or compute it) or use some class to store your numbers.
The easiest way to do it, in my opinion, would be to use a span.
#include <cstdlib>
#include <iostream>
#include <gsl/span>
int main() {
int numbers[] = {2, 4, 6, 8};
for(auto& num : gsl::span(numbers)) {
cout << "the current number is " << num;
}
system("pause");
}
Notes:
Spans are part of the GSL library. To use them, download the library from here, and add the download path to the compilation command, e.g. g++ -o foo foo.cpp -I/path/to/gsl
In C++20, span will be part of the standard, so you would just use std::span and #include <span>.