Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/container/emplace hint"

From cppreference.com
< cpp‎ | container
(+`emplace_hint` page template (instead of individual ones) for associative containers, and flat adaptors too)
 
m (Wrong page at the wrong time in the wrong place - should be Template:cpp/container/emplace_hint (it's been fixed). This page shall be deleted.)
 
(One intermediate revision by one user not shown)
Line 1: Line 1:
{{cpp/container/{{{1|}}}/title|emplace_hint}}
 
{{cpp/container/{{{1|}}}/navbar}}
 
{{ddcl|since={{cpp/container/if flat|{{{1|}}}|c++23|c++11}}|
 
template< class... Args >
 
iterator emplace_hint( const_iterator hint, Args&&... args );
 
}}
 
  
{{cpp/container/if ord|{{{1|}}}
 
|Inserts a new element into the container as close as possible to the position just before hint.
 
|Inserts a new element into the container, using {{c|hint}} as a suggestion where the element should go.
 
}}
 
 
{{cpp/container/if set|{{{1|}}}
 
|The constructors of the key and mapped value are called with exactly the same arguments as supplied to the function, forwarded with {{c|std::forward<Args>(args)...}}.
 
|The constructor of the element type ({{tt|value_type}}, that is, {{c|std::pair<const Key, T>}}) is called with exactly the same arguments as supplied to the function, forwarded with {{c|std::forward<Args>(args)...}}.
 
}}
 
 
{{cpp/container/note_iterator_invalidation|{{{1|}}}|emplace_hint}}
 
 
===Parameters===
 
{{par begin}}
 
{{cpp/container/if ord|{{{1|}}}
 
|{{par|hint|iterator to the position before which the new element will be inserted}}
 
|{{par|hint|iterator, used as a suggestion as to where to insert the new element}}
 
}}
 
{{par|args|arguments to forward to the constructor of the element}}
 
{{par end}}
 
 
===Return value===
 
Returns an iterator to the newly inserted element. {{cpp/container/if uniq|{{{1|set}}}|
 
If the insertion failed because the element already exists, returns an iterator to the already existing element with the equivalent key.}}
 
 
===Exceptions===
 
<!--{{cpp/container/exceptions|{{{1}}}|emplace_hint}}-->
 
{{cpp/strong exception safety guarantee}}
 
 
===Complexity===
 
<!--{{cpp/container/complexity|{{{1}}}|emplace_hint}}-->
 
{{cpp/container/if flat|{{{1}}}
 
|<!--
 
Logarithmic in the size of the container in general, but amortized constant if the new element is inserted just before {{c|hint}}, plus complexity of emplace into underlying container(s) (typically linear).
 
-->{{todo}}
 
|{{cpp/container/if ord|{{{1|}}}
 
|Logarithmic in the size of the container in general, but amortized constant if the new element is inserted just before {{c|hint}}.
 
|Amortized constant on average, worst case linear in the size of the container.
 
}}
 
}}
 
 
===Example===
 
{{#vardefine:cont|{{{1|map}}}}}
 
{{#switch:{{#var:cont}}
 
|set|unordered_set|flat_set=
 
{{example
 
|code=
 
#include <chrono>
 
#include <cstddef>
 
#include <functional>
 
#include <iomanip>
 
#include <iostream>
 
#include <{{cpp/container/get header|{{#var:cont}}}}>
 
 
const int n_operations = 100'500'0;
 
 
std::size_t set_emplace()
 
{
 
    std::{{#var:cont}}<int> set;
 
    for (int i = 0; i < n_operations; ++i)
 
        set.emplace(i);
 
    return set.size();
 
}
 
 
std::size_t set_emplace_hint()
 
{
 
    std::{{#var:cont}}<int> set;
 
    auto it = set.begin();
 
    for (int i = 0; i < n_operations; ++i)
 
    {
 
        set.emplace_hint(it, i);
 
        it = set.end();
 
    }
 
    return set.size();
 
}
 
 
std::size_t set_emplace_hint_wrong()
 
{
 
    std::{{#var:cont}}<int> set;
 
    auto it = set.begin();
 
    for (int i = n_operations; i > 0; --i)
 
    {
 
        set.emplace_hint(it, i);
 
        it = set.end();
 
    }
 
    return set.size();
 
}
 
 
std::size_t set_emplace_hint_corrected()
 
{
 
    std::{{#var:cont}}<int> set;
 
    auto it = set.begin();
 
    for (int i = n_operations; i > 0; --i)
 
    {
 
        set.emplace_hint(it, i);
 
        it = set.begin();
 
    }
 
    return set.size();
 
}
 
 
std::size_t set_emplace_hint_closest()
 
{
 
    std::{{#var:cont}}<int> set;
 
    auto it = set.begin();
 
    for (int i = 0; i < n_operations; ++i)
 
        it = set.emplace_hint(it, i);
 
    return set.size();
 
}
 
 
double time_it(std::function<std::size_t()> set_test,
 
              const char* what = nullptr,
 
              double ratio = 0.0)
 
{
 
    const auto start = std::chrono::system_clock::now();
 
    const std::size_t setsize = set_test();
 
    const auto stop = std::chrono::system_clock::now();
 
    const std::chrono::duration<double, std::milli> time = stop - start;
 
    if (what != nullptr && setsize > 0)
 
        std::cout << std::setw(8) << time << " for " << what << " (ratio: "
 
                  << (ratio == 0.0 ? 1.0 : ratio / time.count()) << ")\n";
 
    return time.count();
 
}
 
 
int main()
 
{
 
    std::cout << std::fixed << std::setprecision(2);
 
    time_it(set_emplace); // cache warmup
 
    const auto x = time_it(set_emplace, "plain emplace");
 
    time_it(set_emplace_hint, "emplace with correct hint", x);
 
    time_it(set_emplace_hint_wrong, "emplace with wrong hint", x);
 
    time_it(set_emplace_hint_corrected, "corrected emplace", x);
 
    time_it(set_emplace_hint_closest, "emplace using returned iterator", x);
 
}
 
|p=true
 
|output=
 
{{#switch:{{#var:cont}}
 
|set=
 
392.25ms for plain emplace (ratio: 1.00)
 
97.15ms for emplace with correct hint (ratio: 4.04)
 
387.52ms for emplace with wrong hint (ratio: 1.01)
 
84.80ms for corrected emplace (ratio: 4.63)
 
83.67ms for emplace using returned iterator (ratio: 4.69)
 
|unordered_set=
 
146.88ms for plain emplace (ratio: 1.00)
 
168.20ms for emplace with correct hint (ratio: 0.87)
 
168.78ms for emplace with wrong hint (ratio: 0.87)
 
166.58ms for corrected emplace (ratio: 0.88)
 
168.27ms for emplace using returned iterator (ratio: 0.87)
 
|flat_set=
 
...TODO...
 
}}
 
}}
 
|map|unordered_map|flat_map=
 
{{example
 
|code=
 
#include <chrono>
 
#include <cstddef>
 
#include <functional>
 
#include <iomanip>
 
#include <iostream>
 
#include <{{cpp/container/get header|{{#var:cont}}}}>
 
 
const int n_operations = 100'500'0;
 
 
std::size_t map_emplace()
 
{
 
    std::{{#var:cont}}<int, char> map;
 
    for (int i = 0; i < n_operations; ++i)
 
        map.emplace(i, 'a');
 
    return map.size();
 
}
 
 
std::size_t map_emplace_hint()
 
{
 
    std::{{#var:cont}}<int, char> map;
 
    auto it = map.begin();
 
    for (int i = 0; i < n_operations; ++i)
 
    {
 
        map.emplace_hint(it, i, 'b');
 
        it = map.end();
 
    }
 
    return map.size();
 
}
 
 
std::size_t map_emplace_hint_wrong()
 
{
 
    std::{{#var:cont}}<int, char> map;
 
    auto it = map.begin();
 
    for (int i = n_operations; i > 0; --i)
 
    {
 
        map.emplace_hint(it, i, 'c');
 
        it = map.end();
 
    }
 
    return map.size();
 
}
 
 
std::size_t map_emplace_hint_corrected()
 
{
 
    std::{{#var:cont}}<int, char> map;
 
    auto it = map.begin();
 
    for (int i = n_operations; i > 0; --i)
 
    {
 
        map.emplace_hint(it, i, 'd');
 
        it = map.begin();
 
    }
 
    return map.size();
 
}
 
 
std::size_t map_emplace_hint_closest()
 
{
 
    std::{{#var:cont}}<int, char> map;
 
    auto it = map.begin();
 
    for (int i = 0; i < n_operations; ++i)
 
        it = map.emplace_hint(it, i, 'e');
 
    return map.size();
 
}
 
 
double time_it(std::function<std::size_t()> map_test,
 
              std::string what = "", double ratio = 0.0)
 
{
 
    const auto start = std::chrono::system_clock::now();
 
    const std::size_t map_size = map_test();
 
    const auto stop = std::chrono::system_clock::now();
 
    std::chrono::duration<double, std::milli> time = stop - start;
 
    if (what.size() && map_size)
 
        std::cout << std::setw(8) << time << " for " << what << " (ratio: "
 
                  << (ratio == 0.0 ? 1.0 : ratio / time.count()) << ")\n";
 
    return time.count();
 
}
 
 
int main()
 
{
 
    std::cout << std::fixed << std::setprecision(2);
 
    time_it(map_emplace); // cache warmup
 
    const auto x = time_it(map_emplace, "plain emplace");
 
    time_it(map_emplace_hint, "emplace with correct hint", x);
 
    time_it(map_emplace_hint_wrong, "emplace with wrong hint", x);
 
    time_it(map_emplace_hint_corrected, "corrected emplace", x);
 
    time_it(map_emplace_hint_closest, "emplace using returned iterator", x);
 
}
 
|p=true
 
|output=
 
{{#switch:{{#var:cont}}
 
|map=
 
365.08ms for plain emplace (ratio: 1.00)
 
96.54ms for emplace with correct hint (ratio: 3.78)
 
409.40ms for emplace with wrong hint (ratio: 0.89)
 
85.57ms for corrected emplace (ratio: 4.27)
 
84.31ms for emplace using returned iterator (ratio: 4.33)
 
|unordered_map=
 
143.48ms for plain emplace (ratio: 1.00)
 
164.78ms for emplace with correct hint (ratio: 0.87)
 
171.22ms for emplace with wrong hint (ratio: 0.84)
 
166.55ms for corrected emplace (ratio: 0.86)
 
167.41ms for emplace using returned iterator (ratio: 0.86)
 
|flat_map=
 
...TODO...
 
}}
 
}}
 
|{{example}}
 
}}
 
 
===See also===
 
{{dsc begin}}
 
{{dsc inc|cpp/container/dsc emplace|{{{1|}}}}}
 
{{dsc inc|cpp/container/dsc insert|{{{1|}}}}}
 
{{dsc end}}
 
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
 

Latest revision as of 07:56, 30 January 2024