Is the sequencing of this decrement invoking undefined behaviour? - c++

I am looking for confirmation, clarification is this code well defined or not.
It is very common to erase elements of a container in a loop by re-assigning the iterator to the result of the container's erase() function. The loop is usually a little messy like this:
struct peer { int i; peer(int i): i(i) {} };
int main()
{
std::list<peer> peers {0, 1, 2, 3, 4, 5, 6};
for(auto p = peers.begin(); p != peers.end();) // remember not to increment
{
if(p->i > 1 && p->i < 4)
p = peers.erase(p);
else
++p; // remember to increment
}
for(auto&& peer: peers)
std::cout << peer.i << ' ';
std::cout << '\n';
}
Output: 0 1 4 5 6
It occurred to me that the following might be little tidier, assuming it is not invoking undefined behavior:
struct peer { int i; peer(int i): i(i) {} };
int main()
{
std::list<peer> peers {0, 1, 2, 3, 4, 5, 6};
for(auto p = peers.begin(); p != peers.end(); ++p)
if(p->i > 1 && p->i < 4)
--(p = peers.erase(p)); // idiomatic decrement ???
for(auto&& peer: peers)
std::cout << peer.i << ' ';
std::cout << '\n';
}
Output: 0 1 4 5 6
The reasons why I think this works are as follows:
peers.erase() will always return an incremented p, therefore it is safe to decrement it again
peers.erase(p) makes a copy of p so it will not operate on the wrong value due to sequencing reference
p = peers.erase(p) returns a p& so the decrement operates on the correct object reference.
But I have niggling doubts. I am worried I am invoking the bad sequencing rule by using --(p) in the same expression where p is used as a parameter despite the fact that it looks on paper to be okay.
Can anyone see a problem with my assessment here? Or is this well defined?

It depends on the condition that you are using to detect those elements to delete. It will fail if you try to delete the first element as erase will return the new begin() and you are then decrementing it. This is illegal, even if you immediately increment it again.
To avoid this error and because it is more common and readable, I'd stick with the first version.

Second version is - as stated by #DanielFrey - wrong, but if you don't like first version, why just not do something like that:
std::list<int> myList = { 0, 1, 2, 3, 4, 5, 6 };
myList.remove_if(
[](int value) -> bool {
return value > 1 && value < 4;
}
);
/* even shorter version
myList.remove_if([](int value) -> bool {
return (value > 1 && value < 4);
});
*/
for(int value : myList) {
std::cout << value << " ";
}
This gives output:
0 1 4 5 6
Live example.

Related

Comparing returned vectors from recursion tree branches

Suppose I have a given sum, say sum = 4. I am also given a vector = {2,4}. There are two ways to generate the given sum from the given vector (elements may be reused).
One way is just {4} cause 4 = 4.
Second way is {2,2} cause 2 + 2 = 4.
I have to find the shortest possible combination, therefore in this particular case the answer is {4}.
Here is my approach - I go through the tree, and when on the leaf I get a 0, we hit the base case, return {} vector, and fill up the vector while traversing the tree. When I get to a node, I choose the smaller of the two (or more) vectors. This way when I reach the root node, I should get a vector of the shortest combination that can yield me the target sum.
As of yet, I do not care about time constraints as such, I know there's a lot of repetitive computing going on so I will have to memoize it once I can get the basic version correct.
I have been trying to figure why this code is not working. Any insight would be appreciated.
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
vector<int> findBestSum(int targetSum, const vector<int> &elements, vector<vector<int>> &temp) {
if (targetSum == 0)
return {};
else if (targetSum < 0)
return {-1};
else {
vector<int> small;
for (auto &i : elements) {
int remainder = targetSum - i;
vector<int> returnedVector = findBestSum(remainder, elements, temp);
if ((!returnedVector.empty() && find(returnedVector.begin(), returnedVector.end(), -1) == returnedVector.end()) || returnedVector.empty()) {
returnedVector.push_back(i);
temp.push_back(returnedVector);
}
int smallestLength = temp[0].size();
for (auto &j : temp)
if (smallestLength >= j.size())
small = j;
}
return small;
}
}
int main() {
int targetSum = 6;
const vector<int> elements{2, 3, 5}; // answer should be [3,3] however I just get a 3...
vector<vector<int>> temp;
vector<int> bestSumVector = findBestSum(targetSum, elements, temp);
for (auto i : bestSumVector)
cout << i << " ";
}
Update (14th of July, 2021):
After a few busy months I have tried to lock horns with this problem and this time my code looks like this:
#include <iostream>
#include <vector>
#include <map>
#include <numeric>
using namespace std;
bool howSum(int &targetSum, vector<int> &elementVector, vector<int> &howSumVector, vector<vector<int>> &allSums) {
static int originaltargetsum = targetSum;
if (targetSum == 0)
return true;
else if (targetSum < 0)
return false;
else {
for (auto i : elementVector) {
int remainder = targetSum - i;
bool flag = howSum(remainder, elementVector, howSumVector, allSums);
if (flag) {
howSumVector.push_back(i);
if (targetSum == originaltargetsum ||
accumulate(howSumVector.begin(), howSumVector.end(), 0) == originaltargetsum) {
allSums.push_back(howSumVector);
howSumVector.clear();
}
return true;
}
}
return false;
}
}
int main() {
int sum = 8;
vector<int> elements = {1, 4, 5};
vector<vector<int>> allSums = {};
vector<int> workingBench = {};
howSum(sum, elements, workingBench, allSums);
for (auto &i : allSums) {
for (auto &j : i) {
cout << j << " ";
}
cout << endl;
}
}
For this I have sum as 8 and elements as {1, 4, 5}.
Also I'm storing and displaying all possible solutions right now (once that is correctly done, finding shortest vector and memoization should be easy). Possible solutions in this case are:
[1, 1, 1, 1, 1, 1, 1, 1]
[4, 4]
[5, 1, 1, 1]
[4, 1, 1, 1, 1]
Currently my code only shows the first possible combination. I'm pretty sure I'm returning true and false incorrectly, please help me out here.
I took a stab at this. I do have a working solution, hopefully it is what you want:
#include <iostream>
#include <vector>
#include <algorithm>
void howSum(int targetSum, const std::vector<int> & elementVector, const std::vector<int> & howSumVector, std::vector<std::vector<int>> & allSums)
{
static int originaltargetsum = targetSum;
if (targetSum == 0)
{
allSums.push_back(howSumVector);
return;
}
else if (targetSum < 0)
{
return;
}
else
{
for (const auto i : elementVector)
{
// an element less than or equal to 0 would cause an infinite loop
if (i <= 0)
continue;
std::vector<int> newSumVector = howSumVector;
newSumVector.push_back(i);
std::vector<int> newElementVector;
std::copy_if(std::begin(elementVector), std::end(elementVector), std::back_inserter(newElementVector), [i](int element){ return element >= i; });
howSum(targetSum - i, newElementVector, newSumVector, allSums);
}
}
}
int main()
{
int sum = 8;
std::vector<int> elements = { 1, 4, 5 };
std::vector<std::vector<int>> allSums = {};
std::vector<int> workingBench = {};
howSum(sum, elements, workingBench, allSums);
for (const auto & i : allSums)
{
for (const auto & j : i)
{
std::cout << j << " ";
}
std::cout << std::endl;
}
return 0;
}
I think, in general, you were over-thinking or over-engineering the problem. Like others have mentioned, your current code is returning true too early, and nothing besides the first element/combination is tested. With recursion, it is important to take care in your return cases - really, you only want a base case or two, and otherwise you want to recur.
With the solution I have here, the main thing I have added is copying the current combination of elements for each element you need to test. That solves your main issue of not testing every combination of numbers. In addition to that, it seemed better to append to allSums when the targetSum was reached. With those changes, I was able to do away with the bool return value and simplify the code a bit. Running the code above gives these solutions:
1 1 1 1 1 1 1 1
1 1 1 1 4
1 1 1 4 1
1 1 1 5
1 1 4 1 1
1 1 5 1
1 4 1 1 1
1 5 1 1
4 1 1 1 1
4 4
5 1 1 1
This does have some duplicates (because of the order things are tested) but I felt like it is good enough since you only want the smallest solution, 4 4. To find this, you would just need to sort the allSums vector by inner vector size and then take the first entry.
I think you need to change the implementation to correctly process elements of the vector.
In your implementation it doesn't go over all vector items, just the first one.
This is one way to do it if you use vector elements as the first parameter in your function.
vector<int> findBestSum(int element, int targetSum, const vector<int>& elements,
vector<vector<int>>& temp) {
if (targetSum == 0)
return {};
else if (targetSum < 0)
return { -1 };
else {
int remainder = targetSum - element;
vector<int> returnedVector = findBestSum(element, remainder, elements, temp);
if ((!returnedVector.empty() && find(returnedVector.begin(), returnedVector.end(), -1) == returnedVector.end()) || returnedVector.empty()) {
returnedVector.push_back(element);
return returnedVector;
}
return returnedVector;
}
}
int main() {
const int targetSum = 6;
const vector<int> elements{ 2, 3, 5 }; // answer should be [3,3] however I just get a 3...
vector<vector<int>> temp;
for (auto i : elements) {
vector<int> returnedVector = findBestSum(i, targetSum, elements, temp);
if ((!returnedVector.empty() && find(returnedVector.begin(), returnedVector.end(), -1) == returnedVector.end()) || returnedVector.empty())
temp.push_back(returnedVector);
}
if (temp.size() > 0) {
vector<int> bestSum = {};
size_t small = 0;
size_t smallestLength = temp[0].size();
for (auto& j : temp)
if (smallestLength >= j.size()) {
small = j.size();
bestSum = j;
}
for (auto i : bestSum)
cout << i << " ";
}
else
cout << " sum not found" << endl;
}

Why does the simple arithmetic subtraction not work in the "if" condition?

I have 2 arrays with elements in them. I used hashing to get the frequencies of each element which occurs more than one time. mapcheckA contains the frequencies of elements of first array and mapcheckB contains the frequencies of the other array. I am trying to delete/erase any duplicates of elements from both the unordered maps. Here is the code that does it:
for (auto i : mapcheckA) {
if (mapcheckB.find(i.first) != mapcheckB.end()) {
if (i.second >=
mapcheckB.find(i.first)
->second) { // This block of code doesn't work as expected
i.second -= mapcheckB.find(i.first)->second;
mapcheckB.erase(i.first);
} else {
mapcheckB.find(i.first)->second -= i.second;
mapcheckA.erase(i.first);
}
}
}
for (auto i1 : mapcheckA) {
cout << i1.first << "\t" << i1.second << endl;
}
for (auto i : mapcheckB) {
cout << i.first << "\t" << i.second << endl;
}
When I enter elements in such a way that first array contains element with more frequency than in the second array, like this:
arrayA = [ 1, 1, 1, 1, 4, 4 ]; // Here frequency of "1" is 4.
arrayB = [ 2, 2, 1, 1, 3, 3 ]; // Here frequency of "1" is 2.
In this situation the block of code in the "if" condition does not change the frequency of 1 to 2.
If I change the order of arrays, then the code works fine. What am I doing wrong here?
You have two significant bugs:
working on a copy of the data (already identified in comments). Working with a reference means changes will be reflected in original container, rather than discarded when the copy goes out of scope.
for (auto& i : mapcheckA) { // add the &
undefined behavior
In your "else" case, you remove the element that is current in the iteration, invalidating iterator i, but the loop continues to increment i. Program state is indeterminate and this must not be done.
Unfortunately, with a ranged for loop, there is no good way to do this. Your options:
remember the key (or iterator) for later, and remove them after the loop
hand roll the loop for manual iterator incremeting:
for (auto i = begin(mappedA), e = end(mappedA); i != e; ) {
if (...) {
...
++i;
}
else {
...
i = mappedA.erase(i);
}
}
Further aside, you might consider using c++ structured bindings to make the code more readable and do fewer of the same lookups. Putting that all together:
for (auto iterA = begin(mapcheckA), endA = end(mapcheckA); iterA != endA; ) {
auto& [keyA, valueA] = *iterA;
if (auto iterB = mapcheckB.find(keyA); iterB != end(mapcheckB)) {
auto& [keyB, valueB] = *iterB;
if (valueA >= valueB) {
valueA -= valueB;
mapcheckB.erase(iterB);
++iterA;
} else {
valueB -= valueA;
iterA = mapcheckA.erase(iterA);
}
}
}
Note: both halves of the if update the iterA rather than doing it in the for-loop, since one uses ++ and the other takes the result of calling erase.

Arranging odd and even numbers in a vector C++

I have this problem: Given a vector with n numbers, sort the numbers so that the even ones will be on odd positions and the odd numbers will be on even positions. E.g. If I have the vector 2 6 7 8 9 3 5 1, the output should be 2 7 6 9 8 3 5 1 . The count should start from 1. So on position 1 which is actually index 0 should be an even number, on position 2 which is actually index 1 should be an odd number and so on. Now this is easy if the odd and even numbers are the same, let's say 4 even number and 4 odd numbers in the vector, but what if the number of odd numbers differs from the number of even numbers like in the above example? How do I solve that. I attached the code with one of the tries I did, but it doesn't work. Can I get some help please. I ask you to keep it simple that means only with vectors and such. No weird methods or anything cause I'm a beginner and I only know the basics. Thanks in advance!
I have to mention that n initial is globally declared and is the number of vector elements and v_initial is the initial vector with the elements that need to be rearranged.
The task says to add the remaining numbers to the end of the vector. Like if there are 3 odd and 5 even numbers, The 2 extra even numbers should be thrown at the end of the vector
void vector_pozitii_pare_impare(int v_initial[])
{
int v_pozitie[50],c1=0,c2=1;
for (i = 0; i < n_initial; i++)
{
if (v_initial[i] % 2 == 0)
{
bool isTrue = 1;
for (int k = i + 1; k < n_initial; k++)
{
if (v_initial[k] % 2 != 0)
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c1] = v_initial[i];
c1++;
}
else
{
v_pozitie[c1] = v_initial[i];
c1 += 2;
}
}
else
{
bool isTrue = 1;
for (int j = i + 1; j < n_initial; j++)
{
if (v_initial[j] % 2 == 0)
{
isTrue = 0;
}
if (isTrue)
{
v_pozitie[c2] = v_initial[i];
c2++;
}
else
{
v_pozitie[c2] = v_initial[i];
c2 += 2;
}
}
}
}
This may not be a perfect solution and it just popped out right off my mind without being tested or verified, but it's just to give you an idea.
(Let A,B,C,D be odd numbers and 0,1,2 even numbers correspondingly)
Given:
A 0 B C D 1 2 (random ordered list of odd/even numbers)
Wanted:
A 0 B 1 C 2 D (input sequence altered to match the wanted odd/even criteria)
Next, we invent the steps required to get from given to wanted:
// look at 'A' -> match, next
// Result: A 0 B C D 1 2
// look at '0' -> match, next
// Result: A 0 B C D 1 2
// look at 'B' -> match, next
// Result: A 0 B C D 1 2
// look at 'C' -> mismatch, remember index and find first match starting from index+1
// Result: A 0 B C D ->1<- 2
// now swap the numbers found at the remembered index and the found one.
// Result: A 0 B 1 D C 2
// continue until the whole list has been consumed.
As I said, this algorithm may not be perfect, but my intention is to give you an example on how to solve these kinds of problems. It's not good to always think in code first, especially not with a problem like this. So you should first think about where you start, what you want to achieve and then carefully think of how to get there step by step.
I feel I have to mention that I did not provide an example in real code, because once you got the idea, the execution should be pretty much straight forward.
Oh, and just a small remark: Almost nothing about your code is C++.
A simple solution, that is not very efficient would be to split the vector into 2 vectors, that contain even and uneven numbers and then always take one from the even, one from the uneven and then the remainder, from the one that is not completely entered.
some c++ (that actually uses vectors, but you can use an array the same way, but need to change the pointer arithmetic)
I did not test it, but the principle should be clear; it is not very efficient though
EDIT: The answer below by #AAAAAAAAARGH outlines a better algorithmic idea, that is inplace and more efficient.
void change_vector_even_uneven(std::vector<unsigned>& in_vec){
std::vector<unsigned> even;
std::vector<unsigned> uneven;
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if ((*it) % 2 == 0)) even.push_back(*it);
else uneven.push_back(*it);
}
auto even_it = even.begin();
auto uneven_it = uneven.begin();
for (auto it = in_vec.begin(); it != in_vec.end(); it++){
if (even_it == even.end()){
(*it) = (*uneven_it);
uneven_it++;
continue;
}
if (uneven_it == uneven.end()){
(*it) = (*even_it);
even_it++;
continue;
}
if ((it - in_vec.begin()) % 2 == 0){
(*it) = (*even_it);
even_it++;
}
else{
(*it) = (*uneven_it);
uneven_it++;
}
}
}
The solutions is simple. We sort the even and odd values into a data structure. In a loop, we iterate over all source values. If they are even (val & 2 == 0) we add them at the end of a std::deque for evens and if odd, we add them to a std::deque for odds.
Later, we we will extract the the values from the front of the std::deque.
So, we have a first in first out principle.
The std::deque is optimized for such purposes.
Later, we make a loop with an alternating branch in it. We, alternatively extract data from the even queue and then from the odd queue. If a queue is empty, we do not extract data.
We do not need an additional std::vector and can reuse the old one.
With that, we do not need to take care for the same number of evens and odds. It will of course always work.
Please see below one of millions of possible solutions:
#include <iostream>
#include <vector>
#include <deque>
int main() {
std::vector testData{ 2, 6, 7, 8, 9, 3, 5, 1 };
// Show initial data
std::cout << "\nInitial data: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
// We will use a deques to store odd and even numbers
// With that we can efficiently push back and pop front
std::deque<int> evenNumbers{};
std::deque<int> oddNumbers{};
// Sort the original data into the specific container
for (const int number : testData)
if (number % 2 == 0)
evenNumbers.push_back(number);
else
oddNumbers.push_back(number);
// Take alternating the data from the even and the odd values
bool takeEven{ true };
for (size_t i{}; !evenNumbers.empty() && !oddNumbers.empty(); ) {
if (takeEven) { // Take even numbers
if (not evenNumbers.empty()) { // As long as there are even values
testData[i] = evenNumbers.front(); // Get the value from the front
evenNumbers.pop_front(); // Remove first value
++i;
}
}
else { // Now we take odd numbers
if (not oddNumbers.empty()) { // As long as there are odd values
testData[i] = oddNumbers.front(); // Get the value from the front
oddNumbers.pop_front(); // Remove first value
++i;
}
}
// Next take the other container
takeEven = not takeEven;
}
// Show result
std::cout << "\nResult: ";
for (const int i : testData) std::cout << i << ' ';
std::cout << '\n';
return 0;
}
Here is yet another solution (using STL), in case you want a stable result (that is, the order of your values is preserved).
#include <algorithm>
#include <vector>
auto ints = std::vector<int>{ 2, 6, 7, 8, 9, 3, 5, 1 };
// split list to even/odd sections -> [2, 6, 8, 7, 9, 3, 5, 1]
const auto it = std::stable_partition(
ints.begin(), ints.end(), [](auto value) { return value % 2 == 0; });
auto results = std::vector<int>{};
results.reserve(ints.size());
// merge both parts with equal size
auto a = ints.begin(), b = it;
while (a != it && b != ints.end()) {
results.push_back(*a++);
results.push_back(*b++);
}
// copy remaining values to end of list
std::copy(a, it, std::back_inserter(results));
std::copy(b, ints.end(), std::back_inserter(results));
The result ist [2, 7, 6, 9, 8, 3, 5, 1]. The complexity is O(n).
This answer, like some of the others, divides the data and then reassembles the result. The standard library std::partition_copy is used to separate the even and odd numbers into two containers. Then the interleave function assembles the result by alternately copying from two input ranges.
#include <algorithm>
#include <iostream>
#include <vector>
template <typename InIt1, typename InIt2, typename OutIt>
OutIt interleave(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest)
{
for (;;) {
if (first1 == last1) {
return std::copy(first2, last2, dest);
}
*dest++ = *first1++;
if (first2 == last2) {
return std::copy(first1, last1, dest);
}
*dest++ = *first2++;
}
}
void reorder_even_odd(std::vector<int> &data)
{
auto is_even = [](int value) { return (value & 1) == 0; };
// split
std::vector<int> even, odd;
std::partition_copy(begin(data), end(data), back_inserter(even), back_inserter(odd), is_even);
// merge
interleave(begin(even), end(even), begin(odd), end(odd), begin(data));
}
int main()
{
std::vector<int> data{ 2, 6, 7, 8, 9, 3, 5, 1 };
reorder_even_odd(data);
for (int value : data) {
std::cout << value << ' ';
}
std::cout << '\n';
}
Demo on Compiler Explorer
As suggested, I am using vectors and STL.
No need to be a great mathematician to understand v_pozitie will start with pairs of odd and even and terminate with the integers not in the initial pairs.
I am then updating three iterators in v_positie (no need of temporary containers to calculate the result) : even, odd and end,(avoiding push_back) and would code this way :
#include <vector>
#include <algorithm>
void vector_pozitii_pare_impare(std::vector<int>& v_initial, std::vector<int>& v_pozitie) {
int nodd (0), neven (0);
std::for_each (v_initial.begin (), v_initial.end (), [&nodd] (const int& n) {
nodd += n%2;
});
neven = v_initial.size () - nodd;
int npair (neven < nodd ?neven:nodd);
npair *=2;
std::vector<int>::iterator iend (&v_pozitie [npair]), ieven (v_pozitie.begin ()), iodd (&v_pozitie [1]);
std::for_each (v_initial.begin (), v_initial.end (), [&iend, &ieven, &iodd, &npair] (const int& s) {
if (npair) {
switch (s%2) {
case 0 :
*ieven++ = s;
++ieven;
break;
case 1 :
*iodd++ = s;
++iodd;
break;
}
--npair;
}
else *iend++ = s;
});
}
int main (int argc, char* argv []) {
const int N = 8;
int tab [N] = {2, 6, 7, 8, 9, 3, 5, 1};
std::vector<int> v_initial (tab, (int*)&tab [N]);
std::cout << "\tv_initial == ";
std::for_each (v_initial.begin (), v_initial.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
std::vector<int> v_pozitie (v_initial.size (), -1);
vector_pozitii_pare_impare (v_initial, v_pozitie);
std::cout << "\tv_pozitie == ";
std::for_each (v_pozitie.begin (), v_pozitie.end (), [] (const int& s) {std::cout << s << " ";});
std::cout << std::endl;
}

The conditional operator is not allowing the program to terminate

I just learnt about conditional operators and was doing an introductory exercise stating:
Write a program to use a conditional operator to find the elements in
a vector<int> that have odd value and double the value of each such
element.
Here is the code that I wrote:
int main()
{
vector<int> nums = { 1,2,3,4,5,6,7,8,9 };
int i;
auto beg = nums.begin();
while (*beg > 0) // This will always evaluate to true.
{
((*beg) % 2 == 0 && (beg < nums.end()) ? i = 0 : *beg = 2 * (*(beg++)));
/*If the number is even the program will just assign 0 to i*/
}
}
The program terminates AND gives you the correct output if you change the last line to:
((*beg)%2 == 0 && (beg < nums.end()) ? i = 0 : *beg = 2*(*(beg)));
++beg;
Why is this happening?
It stuck because, if the condition ((*beg)%2 == 0 && (beg < nums.end()) is true, the iterator will not increment for checking further. You have only setting i=0. You should increment the iterator as well.
You can use comma operator for this:
while (beg != nums.end() && *beg > 0)
{
(*beg) % 2 == 0 ? (beg++, i): (*beg = 2 * (*beg) , beg++, ++i );
}
Also note that the count i should be initialized before-hand, not in the while loop.
The complete working code as per the requirement would be:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> nums = { 1,2,3,4,5,6,7,8,9 };
int i{0};
auto beg = nums.begin();
while (beg != nums.end() && *beg > 0)
{
(*beg) % 2 == 0 ? (beg++, i): (*beg = 2 * (*beg) , beg++, ++i );
}
for (const int ele : nums)
std::cout << ele << " ";
std::cout << "\ncount: " << i << "\n";
}
Output:
2 2 6 4 10 6 14 8 18
count: 5
That being said, IMO using comma operator along with conditional operator like the above(the task) is not a good coding manner, which will only make confusions for the future readers of your codebase.
Also read: Why is "using namespace std;" considered bad practice?
If you want to double some values and not others, just do it:
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int& num : nums)
num = num % 2 ? 2 * num : num;
for (int num : nums)
std::cout << num << ' ';
std::cout << '\n';
return 0;
}
A conditional expression is an expression; you use it to compute a value. The code in the question does not do that; it uses the conditional expression as a way of selecting side effects, which is better done with an ordinary if statement.

Find the last non-zero element in a std::vector

I'm trying to find the index of the last non-zero element in a std::vector<double>. If the last element in the vector is non-zero then it should return the index of that last element.
I believe I can use std::find_if_not, reverse iterators and std::distance, based on this:
std::find_if_not(amounts.rbegin(), amounts.rend(), 0.0)
where amounts is a std::vector<double>, but I'm having difficulty in combining this with std::distance and a forward iterator amounts.begin().
Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?
I'm using C++11.
Example:
std::vector<double> v{1.32, 1.423, 2.543, 3.534, 4.2, 0};
auto result1 = std::find_if(std::rbegin(v), std::rend(v), [](auto& v) { return std::fabs(v - 0) > std::numeric_limits<double>::epsilon(); } );
if (result1 != std::rend(v)) {
std::cout << *result1 << "\n";
std::cout << std::distance(std::begin(v), (result1 + 1).base());
}
outputs:
4.2
4
[edit]
more explanation on:
std::fabs(v - 0) > std::numeric_limits<double>::epsilon(); }
in OP question there was:
Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?
so this is such tolerance check, you can replace epsilon use with some other value.
A simple for loop can also do the trick, see live sample: http://ideone.com/dVNOKk
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{1, 2, 3, 4, 1, 2, 3, 0, 4, 1, 2, 3, 4, 0, 0, 0};
for (int i = static_cast<int>(v.size()) - 1; i >= 0; --i) {
if (v.at(i) != 0) {
std::cout << "Last non-zero at: " << i << '\n';
break;
}
}
return 0;
}
Output: Last non-zero at: 12
but I'm having difficulty in combining this with std::distance and a forward iterator amounts.begin()
Reverse iterators have member function base that returns a non-reverse iterator with the relation &*(rit.base() - 1) == &*rit. So, you can use the following:
std::distance(amounts.begin(), found.base()) - 1;
Another option:
amounts.size() - std::distance(amounts.rbegin(), found) - 1
Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?
Yes. In fact, you must use a predicate, even for the exact comparison, since that's what std::find_if_not expects as the third parameter (instead of value of an element).