The emplace functions generally allows to construct container objects directly at the target location. But std::map expects a value type of std::pair<const Key, T>. Now the implementation of emplace needs to instantiate the value type just to get the key to find the insert
location. This cannot happen at the target location, isn't it?
I know, this has been solved in C++17 by try_emplace. I just wonder what
was the idea of this function.
The emplace functions generally allows to construct container objects directly at the target location. But std::map expects a value type of std::pair<const Key, T>. Now the implementation of emplace needs to instantiate the value type just to get the key to find the insert
location. This cannot happen at the target location, isn't it?
I know, this has been solved in C++17 by try_emplace. I just wonder what
was the idea of this function.
Am 25.05.2024 um 19:37 schrieb Paavo Helde:
The cppreference site also gives an example which uses
std::piecewise_construct to emulate try_emplace, so it looks like it
is actually possible to use emplace for a real in-place construction,
albeit in a pretty convoluted way.
And this really works ? The key-value pair has still to be built
from the two forwarding tuples.
Am 29.05.2024 um 10:11 schrieb Paavo Helde:
On 28.05.2024 18:53, Bonita Montero wrote:
Am 25.05.2024 um 19:37 schrieb Paavo Helde:
The cppreference site also gives an example which uses
std::piecewise_construct to emulate try_emplace, so it looks like it
is actually possible to use emplace for a real in-place
construction, albeit in a pretty convoluted way.
And this really works ? The key-value pair has still to be built
from the two forwarding tuples.
Seems so. To be honest I am not sure I fully understand what it does,
this is just a slightly modified example from the cppreference site:
#include <iostream>
#include <tuple>
#include <utility>
#include <map>
#include <string>
struct Foo
{
Foo() {
std::cout << "Constructed a Foo\n";
std::cout << "Constructing at address: " << this << "\n"; >> }
Foo(int, float) {
std::cout << "Constructed a Foo from an int and a float\n"; >> std::cout << "Constructing at address: " << this << "\n"; >> }
void Report() const {
std::cout << "Reporting from address : " << this << "\n"; >> }
};
int main() {
std::map<std::string, Foo> m;
m.emplace(std::piecewise_construct,
std::forward_as_tuple("foo"),
std::forward_as_tuple(10, 3.14f));
The issue would be that the string constructed from your "foo" would
be consumed if the insertion fails. You're not forwarding a string
object which is used otherwise if insertion fails.
Take this:
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<string, string> map;
auto doIt = [&]( bool tryInsert, char const *what )
{
cout << what << endl;
string
key( "hello"sv ),
value( "world"sv );
if( !tryInsert )
map.emplace( piecewise_construct, forward_as_tuple( move(
key ) ), forward_as_tuple( move( value ) ) );
else
map.try_emplace( move( key ), move( value ) );
cout << "\tkey: " << key << endl;
cout << "\tvalue: " << key << endl;
You can find() your key and if it doesn't exist you emplace() the
new node.
Am 30.06.2024 um 18:47 schrieb Andrey Tarasevich:
On 05/25/24 10:41 AM, Bonita Montero wrote:
You can find() your key and if it doesn't exist you emplace() the
new node.
Which is completely unacceptable, ...
Depends on your constraints. Before C++17 there was no other solution
for that and you had to accept that.
Am 30.06.2024 um 18:47 schrieb Andrey Tarasevich:
On 05/25/24 10:41 AM, Bonita Montero wrote:
Which is completely unacceptable, ...
You can find() your key and if it doesn't exist you emplace() the
new node.
Depends on your constraints. Before C++17 there was no other solution
for that and you had to accept that.
The emplace functions generally allows to construct container objects directly at the target location. But std::map expects a value type of std::pair<const Key, T>. Now the implementation of emplace needs to instantiate the value type just to get the key to find the insert
location. This cannot happen at the target location, isn't it?
I know, this has been solved in C++17 by try_emplace. I just wonder what
was the idea of this function.
The emplace functions generally allows to construct container objects directly at the target location. But std::map expects a value type of std::pair<const Key, T>. Now the implementation of emplace needs to instantiate the value type just to get the key to find the insert
location. This cannot happen at the target location, isn't it?
What about using lower_bound() and emplace_hint() instead? That is
available since C++11.
lower_bound() needs a random-access iterator since it does a binary
search.
Am 30.06.2024 um 21:21 schrieb Stefan Große Pawig:
Bonita Montero <Bonita.Montero@gmail.com> writes:
Am 30.06.2024 um 18:47 schrieb Andrey Tarasevich:What about using lower_bound() and emplace_hint() instead? That is
On 05/25/24 10:41 AM, Bonita Montero wrote:
Which is completely unacceptable, ...
You can find() your key and if it doesn't exist you emplace() the
new node.
Depends on your constraints. Before C++17 there was no other solution
for that and you had to accept that.
available since C++11.
lower_bound() needs a random-access iterator since it does a binary
search.
In mainstream implementations `emplace` does not really construct a some local `value_type t` object. Instead, it immediately allocates and[...]> This approach is what permits usage of `emplace` for insertion of
constructs out of the supplied arguments a _node_ object. This node
object is what the `std::map` is literally built of and, of course, that
node object contains a `value_type` object inside.
non-copyable/non-movable objects into the map through `std::piecewise_construct` (which is likely what Stefan refers to in his comment).
Am 01.07.2024 um 13:41 schrieb Bonita Montero:
Am 01.07.2024 um 03:29 schrieb Andrey Tarasevich:
On 06/30/24 2:49 PM, Bonita Montero wrote:
What about using lower_bound() and emplace_hint() instead? That is
available since C++11.
lower_bound() needs a random-access iterator since it does a binary
search.
That's actually one of those curious spots in the standard library:
it doesn't needs a random-access iterator. It needs a forward iterator.
Interesting, but the algorithm for MSVC is still binary partitioning.
Internally a sth. like find_first_if would make more sense. But I think
most developers would be intelligent enough to use find_first_if their-
selfes.
I checked the source and found that the MSVC-code simply uses distance()
and advance(), and both are specialized for non random-access iterators.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 498 |
Nodes: | 16 (2 / 14) |
Uptime: | 56:24:17 |
Calls: | 9,812 |
Calls today: | 14 |
Files: | 13,754 |
Messages: | 6,190,889 |