Avoid temporary copies in C++11 ranged-based for loops. #12169

pull ghost wants to merge 1 commits into bitcoin:master from changing 8 files +19 −19
  1. ghost commented at 11:23 AM on January 12, 2018: none

    The ::value_type of the std::map/std::unordered_map containers is std::pair<const Key, T>.

    Currently a lot of loops drop the const from the iterator which forces the compiler to create a copy, this should be avoided by using the auto keyword.

    A better explanation can be found in Meyer's Effective Modern C++.

    https://books.google.de/books?id=rjhIBQAAQBAJ&lpg=PA41&ots=FmZL15vynY&pg=PA41#v=onepage&q&f=false

  2. fanquake added the label Refactoring on Jan 12, 2018
  3. theuni cross-referenced this on Jan 12, 2018 from issue Add dev guideline limiting auto usage. by TheBlueMatt
  4. laanwj commented at 10:00 AM on February 12, 2018: member

    Currently a lot of loops drop the const from the iterator which forces the compiler to create a copy, this should be avoided by using the auto keyword.

    I don't understand this rationale for using auto. Why doesn't adding const to the iterator have the same effect of avoiding copies?

  5. ryanofsky commented at 12:00 PM on February 12, 2018: contributor

    I don't understand this rationale for using auto. Why doesn't adding const to the iterator have the same effect of avoiding copies?

    If you take a const reference to a type that requires an implicit conversion it will make a copy. Example where loop items are copied:

    vector<pair<int, int>> v;
    ...
    for (const pair<short, short>& p : v);
    

    Using auto would avoid the copy. You could also drop const to trigger a compiler error if the copies are unintended.

  6. dcousens commented at 12:03 PM on February 12, 2018: contributor
    #include <iostream>
    
    struct Foo {
    	Foo () { std::cout << "  Foo()" << std::endl; }
    	Foo (const Foo& z) { std::cout << "  Foo(Foo)" << std::endl; }
    	Foo (const Foo&& z) { std::cout << "  Foo(Foo&&)" << std::endl; }
    };
    using FooInt = std::pair<const Foo, int>;
    
    int main () {
    	std::cout << "Init" << std::endl;
    	const auto bar = {
    		FooInt{ Foo(), 0 },
    		{ Foo(), 1 },
    		{ Foo(), 2 }
    	};
    
    	std::cout << "FooInt : bar" << std::endl;
    	for (FooInt x : bar) {}
    
    	std::cout << "const FooInt& : bar" << std::endl;
    	for (const FooInt& x : bar) {}
    
    	std::cout << "const std::pair<Foo, int>& : bar" << std::endl;
    	for (const std::pair<Foo, int>& x : bar) {}
    
    	std::cout << "const std::pair<const Foo, int>& : bar" << std::endl;
    	for (const std::pair<const Foo, int>& x : bar) {}
    
    	std::cout << "auto : bar" << std::endl;
    	for (auto x : bar) {}
    
    	std::cout << "auto& : bar" << std::endl;
    	for (auto& x : bar) {}
    
    	std::cout << "const auto& : bar" << std::endl;
    	for (const auto& x : bar) {}
    
    	return 0;
    }
    
    $ g++ foo.cpp && ./a.out
    <snip>
    FooInt : bar
      Foo(Foo)
      Foo(Foo)
      Foo(Foo)
    const FooInt& : bar
    const std::pair<Foo, int>& : bar
      Foo(Foo)
      Foo(Foo)
      Foo(Foo)
    const std::pair<const Foo, int>& : bar
    auto : bar
      Foo(Foo)
      Foo(Foo)
      Foo(Foo)
    auto& : bar
    const auto& : bar
    

    Why doesn't adding const to the iterator have the same effect of avoiding copies?

    tl;dr it does have the same effect. AFAIK. Although personally I think auto helps prevent these nits, you weren't wrong in your assumption.

    edit: wait, if you meant const on the std::pair, not the Key, see above.

  7. MarcoFalke commented at 10:42 PM on February 12, 2018: member

    Needs rebase if still relevant

  8. Avoid temporary copies in C++11 ranged-based for loops.
    The ::value_type of the std::map/std::unordered_map containers is
    std::pair<const Key, T>.
    
    Currently a lot of loops drop the const from the iterator which forces
    the compiler to create a copy, this should be avoided by using the auto
    keyword.
    
    A better explanation can be found in Meyer's Effective Modern C++.
    
    https://books.google.de/books?id=rjhIBQAAQBAJ&lpg=PA41&ots=FmZL15vynY&pg=PA41#v=onepage&q&f=false
    53b26f5632
  9. ghost commented at 8:02 PM on February 13, 2018: none

    rebased

  10. jnewbery commented at 6:11 PM on April 4, 2018: member

    needs rebase

  11. Empact commented at 12:15 PM on April 18, 2018: member

    Would be great to avoid these copies, but IMO there is potential documentation / clarity benefit to being explicit about the pair types. How about changing this to just add const to the key types?

  12. MarcoFalke added the label Up for grabs on Apr 19, 2018
  13. laanwj commented at 12:33 PM on April 26, 2018: member

    Going to close this as it seems to be inactive, let me know if you want to pick it up again then I'll reopen.

  14. laanwj closed this on Apr 26, 2018

  15. Empact commented at 9:34 PM on May 14, 2018: member

    I'll take it.

  16. Empact cross-referenced this on May 15, 2018 from issue scripted-diff: Avoid temporary copies when looping over std::map by Empact
  17. fanquake removed the label Up for grabs on May 17, 2018
  18. theuni cross-referenced this on Jun 15, 2018 from issue Avoid copies in range-for loops and add a warning to detect them by theuni
  19. laanwj referenced this in commit 31145a3d7c on Jun 24, 2018
  20. HashUnlimited cross-referenced this on Sep 11, 2018 from issue Avoid copies in range-for loops and add a warning to detect them by HashUnlimited
  21. PastaPastaPasta referenced this in commit 60e0ee4a99 on Jul 7, 2020
  22. PastaPastaPasta referenced this in commit 85f633e26b on Jul 7, 2020
  23. PastaPastaPasta referenced this in commit c298c1ef77 on Jul 8, 2020
  24. bitcoin locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-20 06:55 UTC