Jump to content

C++ for loop

Spev
Go to solution Solved by BlueChinchillaEatingDorito,
1 minute ago, Spev said:

I've never coded in Java but I've heard of for each. Basically it just goes through every element in the hash table? I guess that makes sense. I'm using separate chaining so my buckets are linked lists, and my hash table is a vector. So I guess it goes through every element (linked list) in my vector (hash table) and clears the entire list since it's an STL list it's pretty easy. Ok thanks if it's that simple than that explains it.

If you know C++, then you should be able to read Java code and know what's going on.

But yea, same thing in Java

For(Object temp : objects){
	//do something
}

Where objects is an object (element in C++ terms) is inerrable. It goes through every Object class object in objects, refers each as temp in each iteration of the loop, and you do whatever you need to do with it.   

I need help understanding what exactly this for loop does.

I'm used to seeing for loops like this: for (initialization; condition; increase) statement;

 

        for (auto & hash : hash)
            {
                hash.clear();
            }
hash is a hash table by the way. I also need a little help understanding auto, but as far as I know it's just automatically determines the type needed. 

Current PC build: [CPU: Intel i7 8700k] [GPU: GTX 1070 Asus ROG Strix] [Ram: Corsair LPX 32GB 3000MHz] [Mobo: Asus Prime Z370-A] [SSD: Samsung 970 EVO 500GB primary + Samsung 860 Evo 1TB secondary] [PSU: EVGA SuperNova G2 750w 80plus] [Monitors: Dual Dell Ultrasharp U2718Qs, 4k IPS] [Case: Fractal Design R5]

Link to comment
Share on other sites

Link to post
Share on other sites

If it's similar to how Java works. It's a for each loop. So for each Hash object in hash

Intel® Core™ i7-12700 | GIGABYTE B660 AORUS MASTER DDR4 | Gigabyte Radeon™ RX 6650 XT Gaming OC | 32GB Corsair Vengeance® RGB Pro SL DDR4 | Samsung 990 Pro 1TB | WD Green 1.5TB | Windows 11 Pro | NZXT H510 Flow White
Sony MDR-V250 | GNT-500 | Logitech G610 Orion Brown | Logitech G402 | Samsung C27JG5 | ASUS ProArt PA238QR
iPhone 12 Mini (iOS 17.2.1) | iPhone XR (iOS 17.2.1) | iPad Mini (iOS 9.3.5) | KZ AZ09 Pro x KZ ZSN Pro X | Sennheiser HD450bt
Intel® Core™ i7-1265U | Kioxia KBG50ZNV512G | 16GB DDR4 | Windows 11 Enterprise | HP EliteBook 650 G9
Intel® Core™ i5-8520U | WD Blue M.2 250GB | 1TB Seagate FireCuda | 16GB DDR4 | Windows 11 Home | ASUS Vivobook 15 
Intel® Core™ i7-3520M | GT 630M | 16 GB Corsair Vengeance® DDR3 |
Samsung 850 EVO 250GB | macOS Catalina | Lenovo IdeaPad P580

Link to comment
Share on other sites

Link to post
Share on other sites

Just now, BlueChinchillaEatingDorito said:

If it's similar to how Java works. It's a for each loop. So for each Hash object in hash

I've never coded in Java but I've heard of for each. Basically it just goes through every element in the hash table? I guess that makes sense. I'm using separate chaining so my buckets are linked lists, and my hash table is a vector. So I guess it goes through every element (linked list) in my vector (hash table) and clears the entire list since it's an STL list it's pretty easy. Ok thanks if it's that simple than that explains it.

Current PC build: [CPU: Intel i7 8700k] [GPU: GTX 1070 Asus ROG Strix] [Ram: Corsair LPX 32GB 3000MHz] [Mobo: Asus Prime Z370-A] [SSD: Samsung 970 EVO 500GB primary + Samsung 860 Evo 1TB secondary] [PSU: EVGA SuperNova G2 750w 80plus] [Monitors: Dual Dell Ultrasharp U2718Qs, 4k IPS] [Case: Fractal Design R5]

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, Spev said:

I've never coded in Java but I've heard of for each. Basically it just goes through every element in the hash table? I guess that makes sense. I'm using separate chaining so my buckets are linked lists, and my hash table is a vector. So I guess it goes through every element (linked list) in my vector (hash table) and clears the entire list since it's an STL list it's pretty easy. Ok thanks if it's that simple than that explains it.

If you know C++, then you should be able to read Java code and know what's going on.

But yea, same thing in Java

For(Object temp : objects){
	//do something
}

Where objects is an object (element in C++ terms) is inerrable. It goes through every Object class object in objects, refers each as temp in each iteration of the loop, and you do whatever you need to do with it.   

Intel® Core™ i7-12700 | GIGABYTE B660 AORUS MASTER DDR4 | Gigabyte Radeon™ RX 6650 XT Gaming OC | 32GB Corsair Vengeance® RGB Pro SL DDR4 | Samsung 990 Pro 1TB | WD Green 1.5TB | Windows 11 Pro | NZXT H510 Flow White
Sony MDR-V250 | GNT-500 | Logitech G610 Orion Brown | Logitech G402 | Samsung C27JG5 | ASUS ProArt PA238QR
iPhone 12 Mini (iOS 17.2.1) | iPhone XR (iOS 17.2.1) | iPad Mini (iOS 9.3.5) | KZ AZ09 Pro x KZ ZSN Pro X | Sennheiser HD450bt
Intel® Core™ i7-1265U | Kioxia KBG50ZNV512G | 16GB DDR4 | Windows 11 Enterprise | HP EliteBook 650 G9
Intel® Core™ i5-8520U | WD Blue M.2 250GB | 1TB Seagate FireCuda | 16GB DDR4 | Windows 11 Home | ASUS Vivobook 15 
Intel® Core™ i7-3520M | GT 630M | 16 GB Corsair Vengeance® DDR3 |
Samsung 850 EVO 250GB | macOS Catalina | Lenovo IdeaPad P580

Link to comment
Share on other sites

Link to post
Share on other sites

25 minutes ago, BlueChinchillaEatingDorito said:

If you know C++, then you should be able to read Java code and know what's going on.

But yea, same thing in Java


For(Object temp : objects){
	//do something
}

Where objects is an object (element in C++ terms) is inerrable. It goes through every Object class object in objects, refers each as temp in each iteration of the loop, and you do whatever you need to do with it.   

I think that explains it enough for now. I'll have to look up some more about for each loops later but it seems simple enough. I've just not been exposed to them really yet apparently in either language. Thanks for the help brother.

Current PC build: [CPU: Intel i7 8700k] [GPU: GTX 1070 Asus ROG Strix] [Ram: Corsair LPX 32GB 3000MHz] [Mobo: Asus Prime Z370-A] [SSD: Samsung 970 EVO 500GB primary + Samsung 860 Evo 1TB secondary] [PSU: EVGA SuperNova G2 750w 80plus] [Monitors: Dual Dell Ultrasharp U2718Qs, 4k IPS] [Case: Fractal Design R5]

Link to comment
Share on other sites

Link to post
Share on other sites

4 hours ago, Spev said:

I need help understanding what exactly this for loop does.

I'm used to seeing for loops like this: for (initialization; condition; increase) statement;

 


        for (auto & hash : hash)
            {
                hash.clear();
            }

hash is a hash table by the way. I also need a little help understanding auto, but as far as I know it's just automatically determines the type needed. 

Important to add, auto deduces the type, but the ampersand "&" makes it a reference. That means you're working on the element itself, without it you'd be working on a copy and any changes made would not carry over to the actual element in the sequence.

 

The variable names in this snippet are poorly chosen, the element name "hash" hides the sequence name "hash" inside the loop body. Name hiding is generally considered bad because it's confusing and thus leads to bugs. One should prefer something like this:

	//Just an example, the actual names I'd choose depend on the context.	
	for (auto & hash : hashTable)
   	{
    		hash.clear();
  	}

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

6 hours ago, Unimportant said:

The variable names in this snippet are poorly chosen, the element name "hash" hides the sequence name "hash" inside the loop body. Name hiding is generally considered bad because it's confusing and thus leads to bugs. One should prefer something like this:

Would that even compile?

#include <unordered_map>
#include <random>
#include <iostream>

template <typename Numeric, typename Divisor>
inline constexpr bool isDivisibleBy(Numeric numeric, Divisor divisor)
{
    return ((numeric >= divisor) && ((numeric % divisor) == 0));
}

constexpr auto isEven = [](int test) -> bool { return isDivisibleBy<int, int>(test, 2); };

int main()
{
    std::mt19937 randomEngine{std::random_device{}()};
    std::uniform_int_distribution<int> randomDistribution{0, 100};
    std::unordered_map<int, bool> hash{};
    for (int i = 0; i < 10; i++) {
        int randomNumber{randomDistribution(randomEngine)};
        hash.emplace(randomNumber, isEven(randomNumber));
    }
    for (auto &hash : hash) {
        std::cout << "key \"" << hash.first << "\" is " << (hash.second ? "even" : "odd") << std::endl;
    }
    return 0;
}
Pingu@Z170A-Titanium-PC:~$ g++ -Wall -std=c++14 -o test test.cpp
test.cpp: In function ‘int main()’:
test.cpp:16:23: error: use of ‘hash’ before deduction of ‘auto’
     for (auto &hash : hash) {
                       ^

Whoa, here's some weird stuff. As seen above , it fails to compile for g++ 5.4.0, but a live example here compiles. I wonder what compiler version ideone uses?

EDIT: I tried it on my Arch box and g++ 6.3.1 compiles and runs without error.

Link to comment
Share on other sites

Link to post
Share on other sites

You can break down a "range based for loop" in C++ like this:

Consider a list of some type in C++:

std::vector<int> intList{0, 1, 2, 3, 4, 5, 6,  7, 8, 9}; //List of integers, containing 0 through 9

A common range-base-for loop would look like this:

for (auto &it : intList) {
	std::cout << it << std::endl; //Print each item in the list to stdout, followed by a newline (std::endl)
}

The usage of "auto" in the loop just means the C++ compiler will do pattern matching to infer the type, and if it cannot (because it it ambiguous), will issue a compiler error. In this case, it's very simple for the compiler to see that the argument on the right (intList) is a list of integers, so it deduces the type of the variable "it" to be int. The ampersand (&) tells the compiler that you want "it" to be a reference to the items in intList, not a copy (they reference the same value, so a change it it will change the item in the list). Broken down to a simpler for loop, it would look like this (a little bit of pseudocode):

for (int i = 0; i < intList.size(); i++) {
	int &it = &intList.at(i) //Create a reference variable named it that points to the ith item in intList (note the second ampersand)
	std::cout << it << std::endl;
}

If the right side argument were a hash table (as mentioned in the OP), the it would be deduces differently. Generally, a std::unordered_map is implemented as a hash map, so that is a common usage. In that case, if the hash map were of some types TKey and TValue, it would be deduced to be of type std::pair<TKey, TValue> (a pair of types TKey and TValue).

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, Pinguinsan said:

Would that even compile?


#include <unordered_map>
#include <random>
#include <iostream>

template <typename Numeric, typename Divisor>
inline constexpr bool isDivisibleBy(Numeric numeric, Divisor divisor)
{
    return ((numeric >= divisor) && ((numeric % divisor) == 0));
}

constexpr auto isEven = [](int test) -> bool { return isDivisibleBy<int, int>(test, 2); };

int main()
{
    std::mt19937 randomEngine{std::random_device{}()};
    std::uniform_int_distribution<int> randomDistribution{0, 100};
    std::unordered_map<int, bool> hash{};
    for (int i = 0; i < 10; i++) {
        int randomNumber{randomDistribution(randomEngine)};
        hash.emplace(randomNumber, isEven(randomNumber));
    }
    for (auto &hash : hash) {
        std::cout << "key \"" << hash.first << "\" is " << (hash.second ? "even" : "odd") << std::endl;
    }
    return 0;
}

Pingu@Z170A-Titanium-PC:~$ g++ -Wall -std=c++14 -o test test.cpp
test.cpp: In function ‘int main()’:
test.cpp:16:23: error: use of ‘hash’ before deduction of ‘auto’
     for (auto &hash : hash) {
                       ^

Whoa, here's some weird stuff. As seen above , it fails to compile for g++ 5.4.0, but a live example here compiles. I wonder what compiler version ideone uses?

EDIT: I tried it on my Arch box and g++ 6.3.1 compiles and runs without error.

According to paragraph 6.5.4 of the standard, this range based for loop is equivalent to:

{
   auto && __range = hash; //outer hash as inner hash has not yet been defined, no conflict.
   for (auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin ) 
   {
       auto & hash = *__begin; //fresh definition of inner hash inside it's own scope, hides outer hash as per normal rules.

       hash.clear();
   }
}

So it should work, but there's enough rope to hang yourself without silliness like this.

Link to comment
Share on other sites

Link to post
Share on other sites

5 hours ago, Pinguinsan said:

 


template <typename Numeric, typename Divisor>
inline constexpr bool isDivisibleBy(Numeric numeric, Divisor divisor)
{
    return ((numeric >= divisor) && ((numeric % divisor) == 0));
}

constexpr auto isEven = [](int test) -> bool { return isDivisibleBy<int, int>(test, 2); };

 

Just as a interesting FYI for those who care:

One should be able to write:

isDivisibleBy(test, 2);

Template type deduction should do the rest and remove the need for the explicit <int, int>.

Link to comment
Share on other sites

Link to post
Share on other sites

15 hours ago, Pinguinsan said:

If the right side argument were a hash table (as mentioned in the OP), the it would be deduces differently. Generally, a std::unordered_map is implemented as a hash map, so that is a common usage. In that case, if the hash map were of some types TKey and TValue, it would be deduced to be of type std::pair<TKey, TValue> (a pair of types TKey and TValue).

Important note:

It will actually deduce: std::pair<const TKey, TValue>.

 

Which is another way that auto will save your ass. Since, if you used a range-based for loop with a map declared with, say, std::map<int, char> and tried to iterate it with a const reference to std::pair<int, char>, each iteration will produce a copy since the constness cast will be implicit. That's why using auto is a nice way to avoid situations where code that looks intuitive will actually produce implicit casts (and, therefore, copies).

 

Sorry for being pedantic.

And, if my thought-dreams could be seen,
they'd probably put my head in a guillotine.
But, it's alright, ma, it's life, and life only.

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×