Using std::begin() and std::end() to construct vector from array - c++

I am getting error, while trying to construct vector
int data[] = { 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 }; // source
std::vector<int> vv(data, data + 10); // ok
std::vector<int> vv(std::begin(data), std::end(data + 10)); // Error
GCC output:
main.cpp:59:61: error: no matching function for call to ‘end(int*)’
std::vector<int> vv(std::begin(data), std::end(data + 10));
Why I am getting this error ?

You're getting the error because of the + 10, which causes a decay from array of T to pointer to T. There's an std::end overload to take (a reference to) an array, but not one to take a pointer.
Just use: std::vector<int> vv(std::begin(data), std::end(data));
Alternatively, just use:
std::vector<int> vv{1, 2, 3, 4, 4, 3, 7, 8, 9, 10};
...and skip using the array at all.

Normally you use std::end on an array when you don't know the size. std::end is defined such that it will deduce the size and return a pointer to that offset:
std::vector<int> v(begin(data), end(data));

Related

How to call swap() algorithm on std::list elements?

I'm trying to swap the 2nd and 4th elements in a list, but I can't figure out how to do this. I tried to use vector notation, but it didn't work.
list<int> a1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
swap(a1[1], a1[3]);
A std::list doesn't provide random access indexing, like a std::vector or an array does. You need to use iterators instead, eg:
auto first_node = a1.begin();
auto second_node = std::next(first_node);
auto fourth_node = std::next(first_node, 3);
std::swap(*second_node, *fourth_node);

incorrect output using STL remove_if [duplicate]

This question already has answers here:
std::remove_if - lambda, not removing anything from the collection
(4 answers)
Closed 1 year ago.
I am trying to remove elements from a vector of ints using std::remove_if, but am not getting the required output.
Initial vector members: {0, 1, 2, 1, 3, 1, 4, 5, 1, 6, 1, 7, 1, 8, 1, 9}
Required Output: {0, 2, 3, 4, 5, 6, 7, 8, 9}
Actual Output: {0, 2, 3, 4, 5, 6, 7, 8, 9, 6, 1, 7, 1, 8, 1, 9}
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
class Equal
{
public:
Equal(int a): a_(a){}
bool operator()(int b)
{
return a_ == b;
}
private:
int a_;
};
int main()
{
std::vector<int> vi{0, 1, 2, 1, 3, 1, 4, 5, 1, 6, 1, 7, 1, 8, 1, 9};
std::cout << std::endl;
std::remove_if(vi.begin(), vi.end(), Equal(1));
for (const auto &i : vi) std::cout << i << " ";
return 0;
}
There are just as many elements in the vector before and after the call to
std::remove_if:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range.
... and std::remove_if returns an iterator to the start of the "removed" elements and you can use that iterator to actually erase the elements: See Erase–remove idiom
vi.erase(
std::remove_if(vi.begin(), vi.end(), Equal(1)), // returns iterator
vi.end() // erase to the end
);
Demo
Also note that std::vector got a new specialized function in C++20 that does both things, namely std::erase_if.
Example:
std::erase_if(vi, Equal(1));

Too many initializer values; Initializing Dynamically Allocated Arrays?

Recently while going over C++, I dynamically allocated space for an array and tried to initialize it with 8 default values on the next line.
int* intArray = new int[8];
intArray = {1, 2, 3, 4, 5, 6, 7, 8};
Visual Studio didn't like that, and underlined the 2 in red, as if there is a problem there, only to give me the error "too many initializer values"
I don't know if I used incorrect syntax or if you're just not allowed to set the value of an array that way after declaration. Any ideas?
Okay, it seems this also isn't working for regular non-pointer arrays too, I must be just doing something dumb.
intArray is not an array, it's a pointer. A pointer can't be initialized with an initializer list.
Dynamic allocated memory can be initialized at the moment of allocation:
int* intArray = new int[8] {1, 2, 3, 4, 5, 6, 7, 8};
C array can be initialized also at the declaration:
int intArray[8] = {1, 2, 3, 4, 5, 6, 7, 8};
C++ allows static allocation without dimension parameter
int intArray[] = {1, 2, 3, 4, 5, 6, 7, 8};
where for dynamic allocation
int *intArray = new int[8] {1, 2, 3, 4, 5, 6, 7, 8};
the matching dimension must be passed.

Call a function with a part of a larger array

I'm refactoring some code and have decided that I would like to merge a two-dimensional array into a one-dimensional, larger array. The problem is now that I have some functions which take those smaller arrays as parameter and I would prefer to keep their signatures. Is it possible to call a function with only a part of a larger array?
f1 is what I currently have and f2 is what it should look like after refactoring:
#include <array>
void func(std::array<int const, 5> const& arr, int i);
void f1() {
static std::array<std::array<int const, 5>, 2> const arr{{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 0}}};
func(arr[0], 0);
func(arr[1], 1);
}
void f2() {
static std::array<int const, 10> const arr{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//TODO: call func with first and last 5 elements.
}
If you change your function to to take a range of elements as Peter commented, this becomes trivial. You would pass arr.begin() and arr.begin() + 5 for the first array and arr.begin() + 5, arr.end() for the second.
void func(int* b, int* e, int i);
You can also take a span just to make things cleaner. Here gsl::span is used but you can write your own if you want:
#include <gsl/span>
void func(gsl::span<int> s, int i);
static std::array<int const, 10> const arr{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
func( {arr.begin(), arr.begin() + 5}, 0 );
func( {arr.begin() + 5, arr.end()}, 1 );

How to create a 2D array in C++ using this specific container

I'm trying to port a
int a[][]
from Java to C++. I'm using this class as a container ArrayRef for ints because it handles references, and the project uses it extensively. In the AbstractReader class I declared
const ArrayRef<int> START_END_PATTERN_;
const ArrayRef<int> MIDDLE_PATTERN_;
const ArrayRef<ArrayRef<int> > L_PATTERNS_;
const ArrayRef<ArrayRef<int> > L_AND_G_PATTERNS_;
and
static int START_END_PATTERN[];
static int MIDDLE_PATTERN[];
static int L_PATTERNS[10][4];
static int L_AND_G_PATTERNS[20][4];
Note the trailing underscore to differentiate the two variables.
I'm not sure what to do in order to initialize the two-dimensional ArrayRef. What I'm posting here will segfault because those ArrayRefs are being allocated on the stack. Anybody have a clever way to do this?
The only way I've actually managed to get it to work is using a ArrayRef< Ref<ArrayRef<int> > > by making ArrayRef inherit from Counted, which is basically a class that allows for Reference Counting in C++. But in order to access the elements I hen have to do something like *(foo[i])[j], which is slightly nastier than foo[i][j].
int AbstractReader::L\_AND\_G_PATTERNS[20][4] = {
{3, 2, 1, 1}, // 0
{2, 2, 2, 1}, // 1
{2, 1, 2, 2}, // 2
{1, 4, 1, 1}, // 3
{1, 1, 3, 2}, // 4
{1, 2, 3, 1}, // 5
{1, 1, 1, 4}, // 6
{1, 3, 1, 2}, // 7
{1, 2, 1, 3}, // 8
{3, 1, 1, 2}, // 9
// G patterns
{1, 1, 2, 3}, // 0
{1, 2, 2, 2}, // 1
{2, 2, 1, 2}, // 2
{1, 1, 4, 1}, // 3
{2, 3, 1, 1}, // 4
{1, 3, 2, 1}, // 5
{4, 1, 1, 1}, // 6
{2, 1, 3, 1}, // 7
{3, 1, 2, 1}, // 8
{2, 1, 1, 3} // 9
};
AbstractReader::AbstractReader()
: decodeRowStringBuffer_(ostringstream::app),
START_END_PATTERN_(START_END_PATTERN, 3),
MIDDLE_PATTERN_(MIDDLE_PATTERN, 5),
L_PATTERNS_(10),
L_AND_G_PATTERNS_(20) {
for (int i = 0; i < 20; i++) {
if (i < 10) {
L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
}
ArrayRef<int> lgpattern((L_AND_G_PATTERNS[i]), 4);
L_AND_G_PATTERNS_[i] = lgpattern;
}
}
What you have should be safe. The (stack allocated) ArrayRefs create heap allocated Arrays to back them, and then share those Arrays.
Edit: Thanks for posting Counted. Took a bit of work, but I think I see what's going on.
Solution: Don't declare L_PATTERNS_ or L_AND_G_PATTERNS_ as const. Alternately, const_cast to get the desired operator[]. E.g.
const_cast<ArrayRef<ArrayRef<int> > &>(L_PATTERNS_)[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
Rationale:
In AbstractReader, you declare:
const ArrayRef<ArrayRef<int> > L_PATTERNS_;
Then in its constructor, you attempt an assignment:
AbstractReader::AbstractReader() :
{
...
L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
...
}
Since L_PATTERNS_ is const, L_PATTERNS_[i] invokes a method from ArrayRef<ArrayRef<int> >:
T operator[](size_t i) const { return (*array_)[i]; }
This returns a brand new copy of what was at L_PATTERNS_[i]. The assignment then occurs (into a temporary), leaving the original unchanged. When you later go back to access L_PATTERNS_[xxx], you're looking at the original, uninitialized value (which is a NULL reference/pointer). Thus the segfault.
Somewhat surprising is that ArrayRef even allows this assignment. Certainly it breaks the "Principle of Least Surprise". One would expect the compiler to issue an error. To make sure that the compiler is more helpful in the future, we need to give a slightly different definition of ArrayRef's operator[] const (Array.h:121), such as:
const T operator[](size_t i) const { return (*array_)[i]; }
or perhaps (with caveats):
const T& operator[](size_t i) const { return (*array_)[i]; }
After making either change, the compiler disallows allow the assignment. GCC, for example, reports:
error: passing 'const common::ArrayRef<int>' as 'this' argument of 'common::ArrayRef<T>& common::ArrayRef<T>::operator=(const common::ArrayRef<T>&) [with T = int]' discards qualifiers
Causes may be several. For instance, you don't include in your paste the "Counted" class, and at some point, a->retain() is called (line 130). This method is not shown.