Insert custom class with template into std::map - c++

I have written my own class and I want to insert it into a map. See the example below:
#include <iostream>
#include <string>
#include <map>
#include <memory>
#include <mutex>
template <class T>
class A {
public:
T a;
A() = default;
~A() = default;
A(T i) { a = i; }
};
int main()
{
std::pair<int,A<int>> p;
p = std::make_pair<int,A<int>>(9,A<int>(1));
std::map<int, A<int>> m;
m.emplace(1,A<int>(1));
}
When I try to compile this, I get an enormous error. Please help interpret it. :)
See error here:
http://cpp.sh/9nc35
EDIT:
I had the typo, thanks! Though, the other problem I was struggling with first arose now. Seems like it is because of the mutex? Why?

Your map is defined as:
std::map<int, std::unique_ptr<A<int>>>
But in the next line you're trying to pass an std::pair<int, A<int>> to m.emplace() as the key.
I think you just want to do:
m.emplace(9, std::make_unique<A<int>>(1));
// ^
// Not `p`

You are trying to insert/emplace pair (pair<...>, A) into your map, while you've specified it's key as an int. You most-likely want m.emplace(9,std::make_unique<A<int>>(1)); (see 9 instead of p) or just m.insert(p); (would work fine in your cpp.sh).
Furthermore, your use of unique_ptr here is most-likely wrong/unwarranted and only complicates things. See fixed up example here: http://cpp.sh/3d2hw
Also, you may study STL collections/see some basic examples over at https://en.cppreference.com (https://en.cppreference.com/w/cpp/container/map/map for some map construction examples).

Related

std::map with structs as values

I have an issue where I need to keep a map of, e.g. vectors, of items, each vector has a corresponding indicator valid for all items for a given key in the map
I guess it could be map of pairs (map<string,pair<vector,bool>>) but that would e very confusing...
So
I wanted to ask you about code like that:
Would this be considered a correct implementation of the problem, is there any potential issue with this? When I add a new key with myMap["KEY"] nothing can ever break because it autoinitializes my struct? Can anything go wrong here?
#include <iostream>
#include <vector>
#include <map>
using namespace std;
struct ListOfItemsWithIndicator
{
bool _indicator;
vector<int> _items;
ListOfItemsWithIndicator(): _indicator(false) {}
};
int main() {
std::map<std::string,ListOfItemsWithIndicator> myMap;
myMap["ONE"]._items.push_back(1);
std::cout << myMap["ONE"]._items[0];
return 0;
}

Inserting non-const pair into `std::unordered_map` is slower than const pair

I have some code like these (from cppcon), when inserting a non-const pair into a unordered_map, the performance is very different to inserting with a const one.
#include <algorithm>
#include <chrono>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <vector>
using namespace std;
struct StopWatch {
StopWatch() : clk{std::chrono::system_clock::now()} {}
~StopWatch() {
auto now = std::chrono::system_clock::now();
auto diff = now - clk;
cout << chrono::duration_cast<chrono::microseconds>(diff).count() << "ms"
<< endl;
}
decltype(std::chrono::system_clock::now()) clk;
};
void Benchmark_Slow(int iters) {
std::unordered_map<string, int> m;
std::pair<const string, int> p = {};
while (iters--)
m.insert(p);
}
void Benchmark_Fast(int iters) {
std::unordered_map<string, int> m;
const std::pair<const string, int> p = {};
while (iters--)
m.insert(p);
}
int main(void) {
{
StopWatch sw;
Benchmark_Fast(1000000);
}
{
StopWatch sw;
Benchmark_Slow(1000000);
}
return 0;
}
A online demo: Compiler Explorer
128247ms
392454ms
It seems that the const qualifier let the compiler to choose the unordered_map::insert(const value_type&) overload instead of the unordered_map::insert( P&& value ).
cppreference: unordered_map::insert
But I think that a forwarding templated universal reference insert(P&& value) would be the same as an insert with const lvalue reference, an identical copy operation.
But the emplace one(with non-const pair) runs much slower than insert one(with const pair).
Am I missing something here ? Or if this is something has a keyword to be searched on the google, I didn't find something answers that. Thank you in advance.
I think I do found a possible explanation.
from emplace it describe that if insertion fails, the constructed element would be destroyed immediately.
I follow the assembly code compiled with libstd++ of unordered_map::emplace (which accept templated argument and do std::forward) and unordered_map::insert link provided by #Jarod42, I the emplace one always allocate a new hash_node before it check if the key already in the map, because it's templated and it didn't know the argument type (maybe it only know it's is_convertible_to), so it do the construction before examine the key. The one in libc++ seems recognize the type is a const reference thus do the same as the insert one, copy construct occurs only if the key is not exsist.
When I modified the code with different key to be inserted, the difference gone away. quick C++ benchmark
I don't know did I miss something else. I' m sorry for this trivial problem was posted.

priority queue of unique_ptr comparator

i have a priority queue that stores shared_ptr<obj>. in these obj's there is a method that returns a certain value e.g obj.method1() would return an int. I want to order the queue in ascending order of this value. I tried writing a compare class in the same file but when i add it in as the 3rd parameter it says use of undeclared identifier(I don't have access to the main function that actually runs the code) I also tried using std::greater<shared_ptr<Searchable>> as the 3rd parameter, but I'm not sure if that was the write solution. any help would be appreciated.
priority_queue<shared_ptr<obj>, vector<shared_ptr<obj>>, std::greater<shared_ptr<obj>> > Q;
That is what i have right now but i dont think its working like i wanted it to
Does this work for you?
#include <memory>
#include <queue>
#include <vector>
class obj {
public:
int method1() const { return 123; }
};
using obj_ptr = std::shared_ptr<obj>;
class obj_ptr_comparator {
int operator()(const obj_ptr& lhs, const obj_ptr& rhs)
{
return lhs.get()->method1() < rhs.get()->method1();
}
};
std::priority_queue<obj_ptr, std::vector<obj_ptr>, obj_ptr_comparator> my_queue;
To clarify: The item you'll get with a my_queue.pop() will be the one with the highest value of method1() (because we're essentially running std::less, the default comparator, on the method1() value instead of the shared pointer). See also the cppreference.com entry on std::priority_queue.

class with unique_ptr problems

When using emplace_back a constructor must exist for the parameters passed (k,v) thus I need the constructor below. However since I use unique_ptr it complains about not being able to access 'delete' which I believe means I'm doing something that allows me to have more then one pointer.
I can't figure out the syntax. How do I write this constructor the right way?
struct KV{
unique_ptr<string> k, v;
KV(){}
KV (unique_ptr<string> k_,unique_ptr<string> v_):k(move(k_)),v(move(v_)){}
};
Your constructor is OK. A possible problem is that you are not moving the two unique_ptrs when supplying them to your constructor:
#include <memory>
#include <string>
using namespace std;
struct KV{
unique_ptr<string> k, v;
KV(){}
KV (unique_ptr<string> k_,unique_ptr<string> v_):k(move(k_)),v(move(v_)){}
};
int main()
{
unique_ptr<string> p1(new string());
unique_ptr<string> p2(new string());
// KV v(p1, p2); // ERROR!
KV kv(move(p1), move(p2)); // OK
vector<KV> v;
v.emplace_back(move(p1), move(p2)); // OK
}
UPDATE:
When VS2012 was shipped, VC11 did not support variadic templates. The correct implementation of emplace_back() should be variadic, but MS provided a dummy one. When the CTP has been shipped, only the compiler has been updated with support for variadic templates, but the STL hasn't been updated. Therefore, you still get the error.
There is not much to do about this if you can't change your compiler, apart from waiting for the next release of the product to be shipped. In the meanwhile, avoid using emplace_back() and use push_back() instead.
You haven't mentioned what container you're trying to emplace_back into, but assuming it is a vector, if your KV struct is really that simple, there's no need to declare any constructors. Just use aggregate initialization.
#include <memory>
#include <string>
#include <utility>
#include <vector>
using namespace std;
struct KV
{
unique_ptr<string> k, v;
// KV(){}
// KV (unique_ptr<string> k_,unique_ptr<string> v_):k(move(k_)),v(move(v_)){}
};
int main()
{
unique_ptr<string> p1(new string());
unique_ptr<string> p2(new string());
KV v{move(p1), move(p2)}; // initialize an instance
// this step is not necessary, you can skip it
vector<KV> vec;
vec.emplace_back(KV{move(v.k), move(v.v)});
}

Initializing stl classes with template parameters

I am trying to do declare a stl map with template parameters like so:
( assume T as typename like so : template <class T>)
map<T, T> m; ( in .h file )
It compiles fine. now in my cpp file, when I want to insert into the map, i am not able to. The only methods i get on intellisense are "at" and "swap" methods.
Any ideas? Anyone please?
Thanks in advance.
here is sample code:
#pragma once
#include <iostream>
#include <map>
using namespace std;
template <class T>
class MySample
{
map<T, T> myMap;
//other details omitted
public:
//constructor
MySample(T t)
{
//here I am not able to use any map methods.
//for example i want to insert some elements into the map
//but the only methods I can see with Visual Studio intellisense
//are the "at" and "swap" and two other operators
//Why???
myMap.
}
//destructor
~MySample(void)
{
}
//other details omitted
};
The usual ways to insert key-value pairs into a std::map are the index-operator syntax as well as the insert function. I'll assume std::string for keys and int for values for the sake of the example:
#include <map>
#include <string>
std::map<std::string,int> m;
m["hello"] = 4; // insert a pair ("hello",4)
m.insert(std::make_pair("hello",4)); // alternative way of doing the same
If you can use C++11, you may use the new uniform initialization syntax instead of the make_pair call:
m.insert({"hello",4});
And, as said in the comments, there is
m.emplace("hello",4);
in C++11, which constructs the new key-value pair in-place, rather than constructing it outside the map and copying it in.
I should add that since your question is actually about initialization, rather than inserting fresh elements, and given that indeed you do this in the constructor of MyClass, what you should really do (in C++11) is this:
MySample(T t)
: myMap { { t,val(t) } }
{}
(Here I assume there is some function val which generates the value to store for t in the map.)