Insert pair containig non copyable object into map - c++

Given this map:
map<string,pair<mutex,set<string>>> m;
I would like to insert new elements at a key if they don't exist already. I could do this using the operator[], i.e.:
string possibly_new_key{"foo"};
m[possibly_new_key];
this will default construct my pair<mutex,set>, which is also what I want. The problem is that the performance of my program is my first and last concern. For that reason I would like to use map::insert or map::emplace_hint and use a hint (which I have to compute beforehand anyways) to "insert if it doesn't exist". But I cannot figure out how to call that function correctly because no matter what I try, either
std::pair default construction is ill-formed, or
std::mutex is not copyable and compilation fails.
What I kind of want (and doesn't work):
auto it=m.lower_bound(possibly_new_key);
//do_stuff_with_it(it);
auto new_value=make_pair(mutex{},set<string>{});
m.emplace_hint(it, piecewise_construct, forward_as_tuple(possibly_new_key), forward_as_tuple(new_value));
Is there a way to accomplish this using a hint, and either just default constructing the new value or providing a default constructed one and moving it?

Found out how it works!
emplace can actually take empty parameters to default construct piecewise. With std::forward_as_tuple() such a parameter is passed. So what I ended up with was:
m.emplace_hint(it, piecewise_construct, forward_as_tuple(possibly_new_key), forward_as_tuple());
This solution does everything I wanted in the first place, it uses a hint to possibly have amortized constant complexity and it default constructs the mapped type in place.

All the elements of the standard containers must be copyable.
You can use shared pointers as copyable elements:
struct MutexSetStr
{
std::mutex mutex;
std::set<std::string> data;
};
std::map< std::string, std::shared_ptr<MutexSetStr> > m;
std::shared_ptr<MutexSetStr> new_value(new MutexSetStr);
new_value.mutex.reset(new std::mutex);
m[new_key] = new_value; // or any other method to insert

Related

C++ Error: no matching function for call - when used in class constructor [duplicate]

See also
C++ standard list and default-constructible types
Not a major issue, just annoying as I don't want my class to ever be instantiated without the particular arguments.
#include <map>
struct MyClass
{
MyClass(int t);
};
int main() {
std::map<int, MyClass> myMap;
myMap[14] = MyClass(42);
}
This gives me the following g++ error:
/usr/include/c++/4.3/bits/stl_map.h:419: error: no matching function for call to ‘MyClass()’
This compiles fine if I add a default constructor; I am certain it's not caused by incorrect syntax.
This issue comes with operator[]. Quote from SGI documentation:
data_type& operator[](const key_type& k) - Returns a reference to the object
that is associated with a particular
key. If the map does not already
contain such an object, operator[]
inserts the default object
data_type().
If you don't have default constructor you can use insert/find functions.
Following example works fine:
myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;
Yes. Values in STL containers need to maintain copy semantics. IOW, they need to behave like primitive types (e.g. int) which means, among other things, they should be default-constructible.
Without this (and others requirements) it would be needlessly hard to implement the various internal copy/move/swap/compare operations on the data structures with which STL containers are implemented.
Upon reference to the C++ Standard, I see my answer was not accurate. Default-construction is, in fact, not a requirement:
From 20.1.4.1:
The default constructor is not
required. Certain container class
member function signatures specify the
default constructor as a default
argument. T() must be a well-defined
expression ...
So, strictly speaking, your value type only needs to be default constructible if you happen to be using a function of the container that uses the default constructor in its signature.
The real requirements (23.1.3) from all values stored in STL containers are CopyConstructible and Assignable.
There are also other specific requirements for particular containers as well, such as being Comparable (e.g. for keys in a map).
Incidentally, the following compiles with no error on comeau:
#include <map>
class MyClass
{
public:
MyClass(int t);
};
int main()
{
std::map<int, MyClass> myMap;
}
So this might be a g++ problem.
Check requirements of stored type of the stl::map. Many stl collection require that stored type contains some specific properties (default constructor, copy constructor, etc.).
Constructor without arguments is needed by the stl::map, because it's used, when operator[] is invoked with the key, which hasn't already been kept by the map. In this case the operator[] inserts the new entry consisting of the new key and value constructed using parameterless constructor. And this new value is then returned.
assume you have the following
class Person
{
public:
Person(int age) :age(age){}
Person() {} // default ctor
int age;
};
map<int, Person> m;
// accessing not-existent key, results in assigning default value to that key
m[10];
// creates default object for key:20 first then assigns age
m[20].age = 32;
what should happen if you wanna assign age for a nonexistent key?
for languages with null type such as javascript the map returns null and its is up to user to check for it before accessing the object or its internal fields.
c++ went a different approach and creates the Person using default constructor so the null is avoided all together
Check if:
You forgot the ';' after class declaration.
MyType should've been declared accordingly.
No default constructor there...
The std::map declaration seems correct, I think.
Most likely because std::pair requires it. std::pair holds two values using value semantics so you need to be able to instantiate them without parameters. So the code uses std::pair in various places to return the map values to the caller and this is commonly done by instantiating an empty pair and assigning the values into it before returning the local pair.
You could get around this with smart pointers using a map<int, smartptr<MyClass> > but that adds the overhead of checking for null pointers.

Error when creating instance of unordered map [duplicate]

See also
C++ standard list and default-constructible types
Not a major issue, just annoying as I don't want my class to ever be instantiated without the particular arguments.
#include <map>
struct MyClass
{
MyClass(int t);
};
int main() {
std::map<int, MyClass> myMap;
myMap[14] = MyClass(42);
}
This gives me the following g++ error:
/usr/include/c++/4.3/bits/stl_map.h:419: error: no matching function for call to ‘MyClass()’
This compiles fine if I add a default constructor; I am certain it's not caused by incorrect syntax.
This issue comes with operator[]. Quote from SGI documentation:
data_type& operator[](const key_type& k) - Returns a reference to the object
that is associated with a particular
key. If the map does not already
contain such an object, operator[]
inserts the default object
data_type().
If you don't have default constructor you can use insert/find functions.
Following example works fine:
myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;
Yes. Values in STL containers need to maintain copy semantics. IOW, they need to behave like primitive types (e.g. int) which means, among other things, they should be default-constructible.
Without this (and others requirements) it would be needlessly hard to implement the various internal copy/move/swap/compare operations on the data structures with which STL containers are implemented.
Upon reference to the C++ Standard, I see my answer was not accurate. Default-construction is, in fact, not a requirement:
From 20.1.4.1:
The default constructor is not
required. Certain container class
member function signatures specify the
default constructor as a default
argument. T() must be a well-defined
expression ...
So, strictly speaking, your value type only needs to be default constructible if you happen to be using a function of the container that uses the default constructor in its signature.
The real requirements (23.1.3) from all values stored in STL containers are CopyConstructible and Assignable.
There are also other specific requirements for particular containers as well, such as being Comparable (e.g. for keys in a map).
Incidentally, the following compiles with no error on comeau:
#include <map>
class MyClass
{
public:
MyClass(int t);
};
int main()
{
std::map<int, MyClass> myMap;
}
So this might be a g++ problem.
Check requirements of stored type of the stl::map. Many stl collection require that stored type contains some specific properties (default constructor, copy constructor, etc.).
Constructor without arguments is needed by the stl::map, because it's used, when operator[] is invoked with the key, which hasn't already been kept by the map. In this case the operator[] inserts the new entry consisting of the new key and value constructed using parameterless constructor. And this new value is then returned.
assume you have the following
class Person
{
public:
Person(int age) :age(age){}
Person() {} // default ctor
int age;
};
map<int, Person> m;
// accessing not-existent key, results in assigning default value to that key
m[10];
// creates default object for key:20 first then assigns age
m[20].age = 32;
what should happen if you wanna assign age for a nonexistent key?
for languages with null type such as javascript the map returns null and its is up to user to check for it before accessing the object or its internal fields.
c++ went a different approach and creates the Person using default constructor so the null is avoided all together
Check if:
You forgot the ';' after class declaration.
MyType should've been declared accordingly.
No default constructor there...
The std::map declaration seems correct, I think.
Most likely because std::pair requires it. std::pair holds two values using value semantics so you need to be able to instantiate them without parameters. So the code uses std::pair in various places to return the map values to the caller and this is commonly done by instantiating an empty pair and assigning the values into it before returning the local pair.
You could get around this with smart pointers using a map<int, smartptr<MyClass> > but that adds the overhead of checking for null pointers.

declaring a map with its value type is a class [duplicate]

See also
C++ standard list and default-constructible types
Not a major issue, just annoying as I don't want my class to ever be instantiated without the particular arguments.
#include <map>
struct MyClass
{
MyClass(int t);
};
int main() {
std::map<int, MyClass> myMap;
myMap[14] = MyClass(42);
}
This gives me the following g++ error:
/usr/include/c++/4.3/bits/stl_map.h:419: error: no matching function for call to ‘MyClass()’
This compiles fine if I add a default constructor; I am certain it's not caused by incorrect syntax.
This issue comes with operator[]. Quote from SGI documentation:
data_type& operator[](const key_type& k) - Returns a reference to the object
that is associated with a particular
key. If the map does not already
contain such an object, operator[]
inserts the default object
data_type().
If you don't have default constructor you can use insert/find functions.
Following example works fine:
myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;
Yes. Values in STL containers need to maintain copy semantics. IOW, they need to behave like primitive types (e.g. int) which means, among other things, they should be default-constructible.
Without this (and others requirements) it would be needlessly hard to implement the various internal copy/move/swap/compare operations on the data structures with which STL containers are implemented.
Upon reference to the C++ Standard, I see my answer was not accurate. Default-construction is, in fact, not a requirement:
From 20.1.4.1:
The default constructor is not
required. Certain container class
member function signatures specify the
default constructor as a default
argument. T() must be a well-defined
expression ...
So, strictly speaking, your value type only needs to be default constructible if you happen to be using a function of the container that uses the default constructor in its signature.
The real requirements (23.1.3) from all values stored in STL containers are CopyConstructible and Assignable.
There are also other specific requirements for particular containers as well, such as being Comparable (e.g. for keys in a map).
Incidentally, the following compiles with no error on comeau:
#include <map>
class MyClass
{
public:
MyClass(int t);
};
int main()
{
std::map<int, MyClass> myMap;
}
So this might be a g++ problem.
Check requirements of stored type of the stl::map. Many stl collection require that stored type contains some specific properties (default constructor, copy constructor, etc.).
Constructor without arguments is needed by the stl::map, because it's used, when operator[] is invoked with the key, which hasn't already been kept by the map. In this case the operator[] inserts the new entry consisting of the new key and value constructed using parameterless constructor. And this new value is then returned.
assume you have the following
class Person
{
public:
Person(int age) :age(age){}
Person() {} // default ctor
int age;
};
map<int, Person> m;
// accessing not-existent key, results in assigning default value to that key
m[10];
// creates default object for key:20 first then assigns age
m[20].age = 32;
what should happen if you wanna assign age for a nonexistent key?
for languages with null type such as javascript the map returns null and its is up to user to check for it before accessing the object or its internal fields.
c++ went a different approach and creates the Person using default constructor so the null is avoided all together
Check if:
You forgot the ';' after class declaration.
MyType should've been declared accordingly.
No default constructor there...
The std::map declaration seems correct, I think.
Most likely because std::pair requires it. std::pair holds two values using value semantics so you need to be able to instantiate them without parameters. So the code uses std::pair in various places to return the map values to the caller and this is commonly done by instantiating an empty pair and assigning the values into it before returning the local pair.
You could get around this with smart pointers using a map<int, smartptr<MyClass> > but that adds the overhead of checking for null pointers.

Emplacing a struct in unordered_map, reference issue

I have the following definition for boost unordered_map
typedef boost::unordered::unordered_map<std::String, CLIENT_STATE> CLIENT_MAP;
Where CLIENT_STATE is an struct defined as follow:
typedef struct{
unsigned char state;
/* socket fd of the client */
int fd;
/* File path requested by the client */
char file_path [255];
/* Current file offset */
unsigned long int offset;
} CLIENT_STATE;
When I try to add an element to CLIENT_MAP using emplace, the CLIENT_MAP creates a separate copy of the element, not related to the original definition. i.e. any modifications to the original element definition, won't do any changes to the element in the unordered_map.
I was told before, that using emplace won't clone the my original element, it will place it directly in the container check the link
So what's the best way to let the changes to the added element in the container affects the original definition and vice versa.
This is what I mean:
CLIENT_STATE new_client;
new_client.offset = 5;
client_map.emplace("Test", new_client);
new_client.offset = 10;
cout << client_map["Test"].offest;
The cout won't print 10, it will print 5.
Currently to solve this issue, after an element to the unordered_map I work on the returned std::pair and do the modification, but I think it is not efficient way to do that.
emplace, allows an object to be constructed from the arguments passed into it without needing to create the object to be passed in first, saving an overhead by removing a copy construction which normally happens as the result of creating objects to be inserted.
You can achieve what you want by use of pointers
typedef boost::unordered::unordered_map<std::String, CLIENT_STATE* > CLIENT_MAP;
But using pointers might prove problematic for memory handling, like object deletion, etc.
You can consider using boost::shared_ptr, something like following :
(I'm no shared_ptr/boost expert)
include <boost/shared_ptr.hpp>
boost::unordered::unordered_map<std::String,
boost::shared_ptr<CLIENT_STATE> > client_map ;
std::string s ="client1" ;
CLIENT_STATE *c1 = new CLIENT_STATE;
//c1->state, c1->id, etc
my_map[t] = c1 ;
If you needn't make copies of the objects stored in the map, you can use C++11's std::unique_ptr
You don't want to use emplace. What you want is called shared pointer semantics. However, for future visitors to this question, it may be useful to explain how to correctly use emplace with an associative container.
As #gha.st correctly commented, emplace will call the constructor of std::pair<std::string, CLIENT_STATE>, which will make copies of the string and CLIENT_STATE objects.
Since C++11, std::pair has an extra constructor overload taking a first argument of tag type std::piecewise_construct_t which allows the members of the std::pair themselves to be emplace-constructed. Observe:
client_map.emplace(std::piecewise_construct,
std::forward_as_tuple("Test"),
std::forward_as_tuple(5));
Now emplace will call the tag-overloaded constructor of pair, which in turn will emplace-construct its two data members from the arguments in the forwarded tuples.
In this case, CLIENT_STATE is an aggregate type, so (before C++20) it doesn't have a constructor which we can call with an int like this. But the above is the general technique to use with typical C++ class types. The best we can do for an aggregate before C++20 is to move-construct it from a temporary:
client_map.emplace("Test", CLIENT_STATE{ 0, 0, "", 5 });
In this case, this is of no help because the members of CLIENT_STATE are not move-constructible, so a move is the same as a copy.

Why does the C++ map type argument require an empty constructor when using []?

See also
C++ standard list and default-constructible types
Not a major issue, just annoying as I don't want my class to ever be instantiated without the particular arguments.
#include <map>
struct MyClass
{
MyClass(int t);
};
int main() {
std::map<int, MyClass> myMap;
myMap[14] = MyClass(42);
}
This gives me the following g++ error:
/usr/include/c++/4.3/bits/stl_map.h:419: error: no matching function for call to ‘MyClass()’
This compiles fine if I add a default constructor; I am certain it's not caused by incorrect syntax.
This issue comes with operator[]. Quote from SGI documentation:
data_type& operator[](const key_type& k) - Returns a reference to the object
that is associated with a particular
key. If the map does not already
contain such an object, operator[]
inserts the default object
data_type().
If you don't have default constructor you can use insert/find functions.
Following example works fine:
myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;
Yes. Values in STL containers need to maintain copy semantics. IOW, they need to behave like primitive types (e.g. int) which means, among other things, they should be default-constructible.
Without this (and others requirements) it would be needlessly hard to implement the various internal copy/move/swap/compare operations on the data structures with which STL containers are implemented.
Upon reference to the C++ Standard, I see my answer was not accurate. Default-construction is, in fact, not a requirement:
From 20.1.4.1:
The default constructor is not
required. Certain container class
member function signatures specify the
default constructor as a default
argument. T() must be a well-defined
expression ...
So, strictly speaking, your value type only needs to be default constructible if you happen to be using a function of the container that uses the default constructor in its signature.
The real requirements (23.1.3) from all values stored in STL containers are CopyConstructible and Assignable.
There are also other specific requirements for particular containers as well, such as being Comparable (e.g. for keys in a map).
Incidentally, the following compiles with no error on comeau:
#include <map>
class MyClass
{
public:
MyClass(int t);
};
int main()
{
std::map<int, MyClass> myMap;
}
So this might be a g++ problem.
Check requirements of stored type of the stl::map. Many stl collection require that stored type contains some specific properties (default constructor, copy constructor, etc.).
Constructor without arguments is needed by the stl::map, because it's used, when operator[] is invoked with the key, which hasn't already been kept by the map. In this case the operator[] inserts the new entry consisting of the new key and value constructed using parameterless constructor. And this new value is then returned.
assume you have the following
class Person
{
public:
Person(int age) :age(age){}
Person() {} // default ctor
int age;
};
map<int, Person> m;
// accessing not-existent key, results in assigning default value to that key
m[10];
// creates default object for key:20 first then assigns age
m[20].age = 32;
what should happen if you wanna assign age for a nonexistent key?
for languages with null type such as javascript the map returns null and its is up to user to check for it before accessing the object or its internal fields.
c++ went a different approach and creates the Person using default constructor so the null is avoided all together
Check if:
You forgot the ';' after class declaration.
MyType should've been declared accordingly.
No default constructor there...
The std::map declaration seems correct, I think.
Most likely because std::pair requires it. std::pair holds two values using value semantics so you need to be able to instantiate them without parameters. So the code uses std::pair in various places to return the map values to the caller and this is commonly done by instantiating an empty pair and assigning the values into it before returning the local pair.
You could get around this with smart pointers using a map<int, smartptr<MyClass> > but that adds the overhead of checking for null pointers.