const auto& to integer with std::min std::max - c++

I have these codes below. What's wrong with the const auto& in this context, it caused unexpected outputs.
It works fine while compiled with gcc-4.8.5, but gets unexpected outputs with gcc-4.9.2.
If I remove the & in const auto&, it works fine with both gcc versions.
// max_dim is a protobuf filed: const auto max_dim = msg.max();
// cat2_num is an element in std::vector<int32_t>: const auto cat2_num = vec[i]
const auto& res_num = std::max(1, std::min(max_dim, cat2_num));
LOG(ERROR) << res_num << ", " << max_dim << ", " << cat2_num
<< ", " << std::max(1, std::min(max_dim, cat2_num));
outputs:
-1392522416, 3, 1, 1
2, 3, 2, 2
3, 3, 3, 3
-1392522416, 3, 1, 1
3, 3, 6, 3
2, 3, 2, 2
-1392522416, 3, 1, 1
-1392522416, 3, 1, 1
2, 3, 2, 2
=========== updated ========
I couldn't reproduce the undefined behavior with these codes:
#include <iostream>
#include <vector>
int main() {
std::vector<int32_t> v = {-1, 0, 1, 2, 3, 6};
const int a = 3;
const auto& b = a;
for(size_t i = 0; i < v.size(); i++) {
const auto& c = v[i];
const auto& d = std::max(1, std::min(b, c));
std::cout << d << ", " << b << ", " << c << std::endl;
}
return 0;
}
output:
1, 3, -1
1, 3, 0
1, 3, 1
2, 3, 2
3, 3, 3
3, 3, 6

Your code has undefined behavior. In
const auto& res_num = std::max(1, std::min(max_dim, cat2_num));
The 1 is a prvalue, so a temporary integer is created that gets bound to the function parameter. This would be okay of max was like
template <typename T> const T max(const T&, const T&);
but instead it is defined like
template <typename T> const T& max(const T&, const T&);
So, if that 1 happens to be the maximum value, then max returns to you a reference to that temporary object that was created. After that, the temporary object is destroyed1, leaving res_num as a dangling reference. To fix the code make res_num a non-reference like
const auto res_num = std::max(1, std::min(max_dim, cat2_num));
and now you get a copy of the correct value.
1: all temporaries are destroyed at the end of the full expression the are created in

#NathanOliver has given clear declaration for the cause. Here is some other related infomation.
const T& is helpful for large objects, but it involves lifetime and aliasing problem. So be careful.
For int, double, pointers values, const T& gains nothing. In this situation, copy is cheaper than reference.
reference: int vs const int&

Related

How to swap rows inside a matrix according to the values of a certain column in ascending order in c++

I am having trouble swapping rows inside a Matrix (nested array) according to the value of a specific column, I am making a console application that displays the results of a group stage in the football world cup so first I insert the results of the games to update the statistics of each team (rows) and generate the input array, but finally, I need to sort the rows according to the number of points of each team (the last position in each row). I need to create a function to generate the output array.
Input array:
inputArray[4][7] {
{0, 2, 1, 1, 3, -2, 2},
{1, 1, 1, 3, 3, 0, 4},
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 2, 2, 0, 4},
}
Output array of the function:
outputArray[4][7] {
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 3, 3, 0, 4},
{1, 1, 1, 2, 2, 0, 4},
{0, 2, 1, 1, 3, -2, 2},
}
The solution is straightforward. But my guess is that this is not what you want.
And, I think that the last value in the row is not the sum . . .
But let us first look at one potential solution:
#include <iostream>
#include <algorithm>
#include <array>
constexpr size_t NumberOfRows = 4u;
constexpr size_t NumberOfColumns = 7u;
using Columns = std::array<int, NumberOfColumns>;
using Array = std::array<Columns,NumberOfRows>;
int main() {
Array array{{ {0, 2, 1, 1, 3, -2, 2},
{1, 1, 1, 3, 3, 0, 4},
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 2, 2, 0, 4} }};
std::sort(std::begin(array), std::end(array), [](const Columns& c1, const Columns& c2) {return c1[6] < c2[6]; });
for (const Columns& c : array) {
for (const int i : c) std::cout << i << '\t';
std::cout << '\n';
}
}
If you want the array to be dynamic, then you may use a std::vector instead. You can then resize the number of rows and then number of columns.
#include <iostream>
#include <algorithm>
#include <vector>
constexpr size_t NumberOfRows = 4u;
constexpr size_t NumberOfColumns = 7u;
using Columns = std::vector<int>;
using Array = std::vector<Columns>;
int main() {
Array array{ {0, 2, 1, 1, 3, -2, 2},
{1, 1, 1, 3, 3, 0, 4},
{2, 0, 1, 3, 1, 2, 6},
{1, 1, 1, 2, 2, 0, 4} };
std::sort(std::begin(array), std::end(array), [](const Columns& c1, const Columns& c2) {return c1[6] < c2[6]; });
for (const Columns& c : array) {
for (const int i : c) std::cout << i << '\t';
std::cout << '\n';
}
}
But I still think that this is the wrong design. Becuase the last value in a row is the sum of other values. It is dependent, can be calculated, and there is no need to store ist.
See the following better design:
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
struct Result {
std::vector<int> values{};
int sum() const { return std::accumulate(values.begin(), values.end(), 0); }
friend std::ostream& operator << (std::ostream& os, const Result& r) {
for (const int i : r.values) os << i << '\t';
return os << "--> " << r.sum();;
}
};
struct Series {
std::vector<Result> results{};
friend std::ostream& operator << (std::ostream& os, const Series& s) {
for (const Result r : s.results) os << r << '\n';
return os;
}
};
int main() {
Series series{{
{{0, 2, 1, 1, 3,-2}},
{{1, 1, 1, 3, 3, 0}},
{{2, 0, 1, 3, 1, 2}},
{{ 1, 1, 1, 2, 2, 0}}
}};
std::sort(series.results.begin(), series.results.end(), [](const Result& r1, const Result& r2) {return r1.sum() < r2.sum(); });
std::cout << series;
}
But you did not give enough information to give a good answer.

Garbage value getting displayed on printing 2d array using row order

I am using gcc compiler on ubuntu 16 , when I am printing value garbage value is getting displayed
#include <bits/stdc++.h>
int Arrayprint(int r, int l, unsigned int* q)
{
r = 3;
l = 4;
for (int i = 0; i < r; i++) {
for (int j = 0; j < l; j++) {
cout << *(q + sizeof(unsigned int) * (i * l + j)); //Garbage getting diplay
cout << *(q + i + j); //this working
cout << "\t";
}
}
cout << "size of unsigned int : " << sizeof(unsigned int); //4
cout << "size of int : " << sizeof(int); //4
}
int main()
{
unsigned int image[R][L] = { { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 } };
unsigned int* q = (unsigned int*)image;
Arrayprint(R, L, q);
}
From what I can tell, you understand at a low level that the address of the ith element of an array of T is base + sizeof(T) * i. That's correct, and it's good that you know that.
However, C and C++ handle this for you already. When you say q + i or q[i], it's actually compiling that into q + sizeof(T)*i anyway (with the latter also dereferencing the result).
So when you say q[sizeof(int)*i], that's actually compiling into *(q + sizeof(int)*sizeof(int)*i), which is clearly not what you wanted.
Thus, the index in the array you actually access is off by a factor of sizeof(int) and results in an out of bounds error, which is where your strange numbers are coming from.
I am using gcc compiler on ubuntu 16 , when I am printing value
garbage value is getting displayed
Instead of trying to fix what's broken in your raw array arimethics, consider using the standard containers:
#include <iostream>
#include <array>
constexpr size_t R = 3;
constexpr size_t L = 4;
using image_t = std::array<std::array<unsigned int, L>, R>;
void Arrayprint(const image_t& q) {
// range based for loops for convenience
for(auto& row : q) { // get references to each row
for(unsigned int colval : row) { // get the column values
std::cout << colval << "\t"; // print the values
}
std::cout << "\n";
}
}
int main() {
image_t image = {{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}};
Arrayprint(image);
}
Output:
1 2 3 4
5 6 7 8
9 10 11 12

Adding elements to std::vector in a repeated way

I want to copy values from one vector to other one that will be stored in a specific order and the second vector will contain more elements than the first one.
For example:
vector<int> temp;
temp.push_back(2);
temp.push_back(0);
temp.push_back(1);
int size1 = temp.size();
int size2 = 4;
vector<int> temp2(size1 * size2);
And now I would like to fill temp2 like that: {2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1}.
Is it possible to do this using only algorithms (e.g. fill)?
Yes, it is possible using std::generate_n algorithm:
int main() {
std::vector<int> base{1, 0, 2};
const int factor = 4;
std::vector<int> out{};
std::generate_n(std::back_inserter(out), base.size() * factor,
[&base, counter=0]() mutable {
return base[counter++ / factor];
});
for(const auto i : out) {
std::cout << i << ' ';
}
}
This code prints: 1 1 1 1 0 0 0 0 2 2 2 2
The key is the lambda used in std::generate_n. It operates on internal counter to know which values, based on base vector (and accessed depending on factor and counter values), to generate.
No, this is quite a specific use case, but you can trivially implement it yourself.
#include <vector>
#include <iostream>
std::vector<int> Elongate(const std::vector<int>& src, const size_t factor)
{
std::vector<int> result;
result.reserve(src.size() * factor);
for (const auto& el : src)
result.insert(result.end(), factor, el);
return result;
}
int main()
{
std::vector<int> temp{2, 0, 1};
std::vector<int> real = Elongate(temp, 4);
for (const auto& el : real)
std::cerr << el << ' ';
std::cerr << '\n';
}
(live demo)

Convert an Eigen::TensorMap to Eigen::Tensor

It's possible to convert an Eigen::Map to a Matrix by assignment:
vector<float> v = { 1, 2, 3, 4 };
auto m_map = Eigen::Map<Eigen::Matrix<float, 2, 2, Eigen::RowMajor>>(&v[0]);
Eigen::MatrixXf m = m_map;
cout << m << endl;
This produces:
1 2
3 4
If I try to do something similar with a Tensor:
vector<float> v = { 1, 2, 3, 4 };
auto mapped_t = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>(&v[0], 2, 2);
Eigen::Tensor<float, 2> t = mapped_t;
I simply get the compiler error YOU_MADE_A_PROGRAMMING_MISTAKE. Is there any way to convert a TensorMap to a Tensor?
Well, Eigen::RowMajor is not the default for Eigen::Tensor which means you are not assigning to the same type which means YOU_MADE_A_PROGRAMMING_MISTAKE. You have to explicitly request swapping the layout.
#include <vector>
#include <unsupported/Eigen/CXX11/Tensor>
int main()
{
std::vector<float> v = { 1, 2, 3, 4 };
auto mapped_t = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>(&v[0], 2, 2);
Eigen::Tensor<float, 2> t = Eigen::TensorLayoutSwapOp<Eigen::Tensor<float, 2, Eigen::RowMajor>>(mapped_t);
}
Using C++14 you could write a nice instantiator function for that.
#include <type_traits>
#include <vector>
#include <unsupported/Eigen/CXX11/Tensor>
namespace Eigen {
template < typename T >
decltype(auto) TensorLayoutSwap(T&& t)
{
return Eigen::TensorLayoutSwapOp<typename std::remove_reference<T>::type>(t);
}
}
int main()
{
std::vector<float> v = { 1, 2, 3, 4 };
auto mapped_t = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>(&v[0], 2, 2);
Eigen::Tensor<float, 2> t = Eigen::TensorLayoutSwap(mapped_t);
}

Need a constexpr for doubling value in for loop

I want to double a value each time a for loop is processed. I have the following code so far:
constexpr size_t doubleN(size_t n, size_t iteration)
{
return n * iteration;
};
const array<size_t, 9> iterationArray = { 1, 2, 3, 4, 5, 6, 7, 8, 10 };
for (size_t i = 1; i <= 10; i++)
{
Insertionsort<double, doubleN(INITIAL_SIZE_N_INSERTIONSORT, iterationArray[i])> insertionsort;
Util<doubleN(INITIAL_SIZE_N_INSERTIONSORT, iterationArray[i])> util;
array<double, doubleN(INITIAL_SIZE_N_INSERTIONSORT, iterationArray[i])> arrayRef;
util.generateRandomDoubleArray(arrayRef);
util.overwriteProcessorCache();
cout << "Measure Insertionsort version 1 with n = " << INITIAL_SIZE_N_INSERTIONSORT << "." << endl;
util.startTimeMeasure();
insertionsort.sortVersion1(arrayRef);
util.stopTimeMeasure();
cout << "Measureing Insertionsort version 1 successful." << endl;
}
My problem is, that I can't double the value returned by the constexpr, cause it always needs a constant value as parameter. Dou you have any idea how to get a constexpr that returns always a value which is doubled based on the prior doubled value?
First, turn your runtime i parameter into compile time value:
template <std::size_t I>
void foo()
{
Insertionsort<double, doubleN(INITIAL_SIZE_N_INSERTIONSORT, I)> insertionsort;
Util<doubleN(INITIAL_SIZE_N_INSERTIONSORT, I)> util;
array<double, doubleN(INITIAL_SIZE_N_INSERTIONSORT, I)> arrayRef;
util.generateRandomDoubleArray(arrayRef);
util.overwriteProcessorCache();
cout << "Measure Insertionsort version 1 with n = " << INITIAL_SIZE_N_INSERTIONSORT << "." << endl;
util.startTimeMeasure();
insertionsort.sortVersion1(arrayRef);
util.stopTimeMeasure();
cout << "Measureing Insertionsort version 1 successful." << endl;
}
then do a loop:
template <size_t ... Is>
void foos()
{
int dummy[] = {0, (foo<Is>(), 0)...};
(void) dummy; // avoid warning for unused variable
}
or with fold expression of C++17:
template <size_t ... Is>
void foos()
{
(foo<Is>(), ...);
}
And call it:
foos<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>();