I am working with vectors and I am initialising them like so:
vector<int> values;
values.push_back(1);
values.push_back(2);
values.push_back(8);
values.push_back(12);
values.push_back(32);
values.push_back(43);
values.push_back(23);
values.push_back(234);
values.push_back(7);
values.push_back(1);
Is there a way, to push_back these elements in a way that is array-like? Like this:
int numbers[2] = {1, 2};
The vector method takes up too many lines, IMO!
In C++11 you can use brace initialization with any container.
std::vector <int> v = {1, 2, 8, 12, 32 ...};
In C++03 you can do this
const int arr[] = {1, 2, 8, 12, 32 ... };
const int size = sizeof arr / sizeof arr[0];
std::vector<int> v(arr, arr + size);
or use boost assign.
#include <boost/assign.hpp>
using namespace boost::assign;
///...
{
std::vector<int> v;
v += 1, 2, 8, 12, 32;
}
There is indeed a way to do this, provided you have your hands on a C++11 compiler:
std::vector<int> values = {1, 2, 3, 4, 5};
This is known as an initializater list. std::vector has a constructor that takes an initializer list (see declaration 7) to initialise its elements.
In C++11, you can do it the same way you do with arrays. std::vector has a constructor that takes a std::initializer_list<T>, which allows it to initialize itself from the list.
In C++03, you can use a temporary array:
int tempValues[] = {1,2,8,12,32,43,23,234,7,1};
std::vector<int> values(tempValues, tempValues + sizeof tempValues / sizeof tempValues[0]);
Related
I cannot seem to sort a 2 dimensional c array with std::sort. I can however sort a one dimensional array. This is in a case where I am being handed a c array in a c++ program and am hoping to sort without copying it over to a std::array. Maybe there is some way to turn it into a std::array without copying it? That sounds doubtful to me as any std::array would then call a destructor on memory that it does not own.
Sorting One dimensional c style array works just fine:
int len = 5;
auto one_dim_less = [](int a, int b){
return a < b;
};
int one_dim[] = {4, 0, 3, 1, 2};
std::sort(one_dim, one_dim + len, one_dim_less);
Attempting to sort two dimensional c style array by second number does not compile:
int len = 5;
auto two_dim_less = [](int a[2], int b[2]){
return a[1] < b[1];
};
int two_dim[][2] = {{1,8}, {2,4}, {3,10}, {4,40}, {5,1}};
std::sort(two_dim, two_dim + len, two_dim_less);
Maybe there is some way to turn it into a std::array without copying
it?
Perhaps not turning into a std::array per se, but an alternative approach might be to cast the 2D C-style arrays into a std::array reference just for the sorting. Doing so in reliance on the standard saying an std::array representation in memory at least begins with its C-style array equivalent. See here under [array.overview§2]:
An array is an aggregate that can be list-initialized with up to N
elements whose types are convertible to T.
In practice, the following usage of reinterpret_cast is most probably safe, but do note that unless there is a special exception for it somewhere in the standard, it would formally be undefined behaviour:
#include <algorithm>
#include <array>
#include <iostream>
int main() {
auto two_dim_less = [](std::array<int, 2>& a, std::array<int, 2>& b) {
return a[1] < b[1]; };
int two_dim[][2] = {{1, 8}, {2, 4}, {3, 10}, {4, 40}, {5, 1}};
std::array<std::array<int, 2>, 5>& arr =
*reinterpret_cast<std::array<std::array<int, 2>, 5>*>(&two_dim);
std::sort(arr.begin(), arr.end(), two_dim_less);
for (int i = 0; i < 5; i++)
std::cout << two_dim[i][0] << ", " << two_dim[i][1] << '\n';
return 0;
}
Output:
5, 1
2, 4
1, 8
3, 10
4, 40
Regarding the use of std::qsort(), note that it is potentially slower than std::sort() due to the latter allowing to inline the comparisons while the former doesn't.
std::sort() requires the objects it's used to sort to be MoveAssginable.
Arrays are not MoveAssginable (nor assignable at all).
Try using an array of structures or std::pairs instead.
I have the following snippet of code having a problem.
I think the compiler can't deduc the type because the type of the elements of values won't b known before compiling. Is that right?
vector values{1, 2, 3, 4, 5, 6};
vector<decltype(values[0])> {values};
ostream_iterator<int> printer{cout," "};
copy(ints.crbegin(),ints.crend(),printer);
The problem here is that values[0] is a int &. See for yourself:
static_assert(std::is_same_v<decltype(values[0]), int &>);
Creating a vector of references is all kinds of wrong. To fix this, just use decltype on the whole vector.
std::vector values{1, 2, 3, 4, 5, 6};
decltype(values) ints(values.cbegin(), values.cend());
For your example, none of this is really necessary because you're just copying a vector. So you can just do this:
std::vector ints = values;
// Or avoid CTAD entirely
auto ints = values;
I cannot seem to sort a 2 dimensional c array with std::sort. I can however sort a one dimensional array. This is in a case where I am being handed a c array in a c++ program and am hoping to sort without copying it over to a std::array. Maybe there is some way to turn it into a std::array without copying it? That sounds doubtful to me as any std::array would then call a destructor on memory that it does not own.
Sorting One dimensional c style array works just fine:
int len = 5;
auto one_dim_less = [](int a, int b){
return a < b;
};
int one_dim[] = {4, 0, 3, 1, 2};
std::sort(one_dim, one_dim + len, one_dim_less);
Attempting to sort two dimensional c style array by second number does not compile:
int len = 5;
auto two_dim_less = [](int a[2], int b[2]){
return a[1] < b[1];
};
int two_dim[][2] = {{1,8}, {2,4}, {3,10}, {4,40}, {5,1}};
std::sort(two_dim, two_dim + len, two_dim_less);
Maybe there is some way to turn it into a std::array without copying
it?
Perhaps not turning into a std::array per se, but an alternative approach might be to cast the 2D C-style arrays into a std::array reference just for the sorting. Doing so in reliance on the standard saying an std::array representation in memory at least begins with its C-style array equivalent. See here under [array.overview§2]:
An array is an aggregate that can be list-initialized with up to N
elements whose types are convertible to T.
In practice, the following usage of reinterpret_cast is most probably safe, but do note that unless there is a special exception for it somewhere in the standard, it would formally be undefined behaviour:
#include <algorithm>
#include <array>
#include <iostream>
int main() {
auto two_dim_less = [](std::array<int, 2>& a, std::array<int, 2>& b) {
return a[1] < b[1]; };
int two_dim[][2] = {{1, 8}, {2, 4}, {3, 10}, {4, 40}, {5, 1}};
std::array<std::array<int, 2>, 5>& arr =
*reinterpret_cast<std::array<std::array<int, 2>, 5>*>(&two_dim);
std::sort(arr.begin(), arr.end(), two_dim_less);
for (int i = 0; i < 5; i++)
std::cout << two_dim[i][0] << ", " << two_dim[i][1] << '\n';
return 0;
}
Output:
5, 1
2, 4
1, 8
3, 10
4, 40
Regarding the use of std::qsort(), note that it is potentially slower than std::sort() due to the latter allowing to inline the comparisons while the former doesn't.
std::sort() requires the objects it's used to sort to be MoveAssginable.
Arrays are not MoveAssginable (nor assignable at all).
Try using an array of structures or std::pairs instead.
What is the simplest way to convert array to vector?
void test(vector<int> _array)
{
...
}
int x[3]={1, 2, 3};
test(x); // Syntax error.
I want to convert x from int array to vector in simplest way.
Use the vector constructor that takes two iterators, note that pointers are valid iterators, and use the implicit conversion from arrays to pointers:
int x[3] = {1, 2, 3};
std::vector<int> v(x, x + sizeof x / sizeof x[0]);
test(v);
or
test(std::vector<int>(x, x + sizeof x / sizeof x[0]));
where sizeof x / sizeof x[0] is obviously 3 in this context; it's the generic way of getting the number of elements in an array. Note that x + sizeof x / sizeof x[0] points one element beyond the last element.
Personally, I quite like the C++2011 approach because it neither requires you to use sizeof() nor to remember adjusting the array bounds if you ever change the array bounds (and you can define the relevant function in C++2003 if you want, too):
#include <iterator>
#include <vector>
int x[] = { 1, 2, 3, 4, 5 };
std::vector<int> v(std::begin(x), std::end(x));
Obviously, with C++2011 you might want to use initializer lists anyway:
std::vector<int> v({ 1, 2, 3, 4, 5 });
Pointers can be used like any other iterators:
int x[3] = {1, 2, 3};
std::vector<int> v(x, x + 3);
test(v)
You're asking the wrong question here - instead of forcing everything into a vector ask how you can convert test to work with iterators instead of a specific container. You can provide an overload too in order to retain compatibility (and handle other containers at the same time for free):
void test(const std::vector<int>& in) {
// Iterate over vector and do whatever
}
becomes:
template <typename Iterator>
void test(Iterator begin, const Iterator end) {
// Iterate over range and do whatever
}
template <typename Container>
void test(const Container& in) {
test(std::begin(in), std::end(in));
}
Which lets you do:
int x[3]={1, 2, 3};
test(x); // Now correct
(Ideone demo)
One simple way can be the use of assign() function that is pre-defined in vector class.
e.g.
array[5]={1,2,3,4,5};
vector<int> v;
v.assign(array, array+5); // 5 is size of array.
One way can be to use the array's bound in one go like this:
int a[3] = {1, 2, 3};
vector<int> v(a, *(&a+1));
So I am playing around with some arrays, and I cannot figure out why this won't work.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
values = numbers;
The following error appear:
Error 1 error C2106: '=' : left operand must be l-value c:\users\abc\documents\visual studio 2012\projects\consoleapplication7\consoleapplication7\main.cpp 9 1 ConsoleApplication7
Why can't I do like that? What does the error mean?
Arrays have a variety of ugly behavior owing to C++'s backward compatibility with C. One of those behaviors is that arrays are not assignable. Use std::array or std::vector instead.
#include <array>
...
std::array<int,5> numbers = {1,2,3};
std::array<int,5> values = {};
values = numbers;
If, for some reason, you must use arrays, then you will have to copy the elements via a loop, or a function which uses a loop, such as std::copy
#include <algorithm>
...
int numbers[5] = {1, 2, 3};
int values[5] = {};
std::copy(numbers, numbers + 5, values);
As a side note, you may have noticed a difference in the way I initialized the values array, simply providing an empty initializer list. I am relying on a rule from the standard that says that if you provide an initializer list for an aggregate, no matter how partial, all unspecified elements are value initialized. For integer types, value initialization means initialization to zero. So these two are exactly equivalent:
int values[5] = {0, 0, 0, 0, 0};
int values[5] = {};
You can't assign arrays in C++, it's stupid but it's true. You have to copy the array elements one by one. Or you could use a built in function like memcpy or std::copy.
Or you could give up on arrays, and use std::vector instead. They can be assigned.
Array names are constant not modifiable l-value, you can't modify it.
values = numbers;
// ^
// is array name
Read compiler error message: "error C2106: '=' : left operand must be l-value" an l-value is modifiable can be appear at lhs of =.
You can assign array name to a pointer, like:
int* ptr = numbers;
Note: array name is constant but you can modify its content e.g. value[i] = number[i] is an valid expression for 0 <= i < 5.
Why can't I do like that?
Basically this constrain is imposed by language, internally array name uses as base address and by indexing with base address you can access content continue memory allocated for array. So in C/C++ array names with be appear at lhs not a l-value.
values = numbers;
Because numbers and values are pointers.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
for(int i = 0;i < 5; i ++){
values[i] = numbers[i];
}
std::array is a good idea, but this is also possible:
struct arr { int values[5]; };
struct arr a{{1, 2, 3}};
struct arr b{{}};
a = b;
Otherwise, use std::memcpy or std::copy.
I think the reason for non-assignability is that C wants to make sure that any pointers to any element in the array would pretty much always remain valid.
Think about vectors that allow dynamic resizing: the older pointers become invalid (horribly) after resizing happens automatically.
PS. With the design philosophy for vectors, the following block works well.
vector<int> v = {1, 5, 16, 8};
vector<int> v_2 = {7, 5, 16, 8};
v_2 = v;