Not able to to do set element insertion inside constructor - c++

I am getting compilation error while inserting values inside constructor Monitor counstructor.
Could you suggest what could be approach for the same as I need to populate this
vector during class instantiation. It works fine with below approach but I don't want to populate the vector separately.
vect1.insert( make_pair(10,20) );
vect1.insert( make_pair(30,49) );
vect1.insert( make_pair(50,60) );
vect1.insert( make_pair(70,80) );
below is the code snippet
#include <iostream>
#include <vector>
#include<algorithm>
#include<memory>
#include <set>
using namespace std;
class Monitor
{
public:
virtual ~Monitor() = default;
explicit Monitor(
const set< pair <double,double> > &vect1
)
{
for (auto &itr : vect1 )
{
std::cout<<"value1 ="<<itr.first<<endl;
std::cout<<"value2="<<itr.second<<endl;
}
}
};
int main()
{ set< pair <double,double> > vect1;
Monitor obj (vect1.insert( make_pair(10,20) ));
return 0;
}
compilation error
error: no matching function for call to ‘Monitor::Monitor(std::pair >, bool>)’
Monitor obj (vect1.insert( make_pair(10,20) ));

You can use constructor of std::set:
Monitor obj({{10,20}, {30,49}, {50,60}, {70,80}});

return type by set::insert is not matching argument of the constructor Monitor(const set< pair <double,double>>&) instead pass the set something like below,
int main()
{
set< pair <double, double> > vect1;
vect1.insert(make_pair(10, 20));
Monitor obj(vect1);
return 0;
}

I wanted to have constructor that recieve a vector that is populated inside the constructor call.
If the vector (or set or whichever) can be a temporary, you can simply create and populate it inside the construction; something as
Monitor obj1{{{10.0, 20.0}, {30.0, 49.0}, {50.0, 60.0}}};
otherwise, if the set must be defined before (as in your example), the solution I see is use the comma operator to populate the set and discard the resulting iterators
std::set<std::pair<double,double>> vect1;
// ..........V <-- observe the parentheses
Monitor obj2{(vect1.insert({10.0, 20.0}), // insert value and discard iterator
vect1.insert({30.0, 49.0}), // insert value and discard iterator
vect1.insert({50.0, 60.0}), // insert value and discard iterator
vect1)}; // pass the populated vect1 to constructor
// ................^ <-- closing parentheses

Monitor obj (vect1.insert( make_pair(10,20) ));
insert returns a std::pair<iterator,bool>, not a std::set<std::pair<double,double>> which is expected by the user defined constructor of Monitor.
According to the user defined Monitor constructor, you need to pass a std::set as an argument. To do so, you can simply pass the std::pair objects to the constructor of std::set:
Monitor obj({{10,20}, {11,21} /*, ...*/});

Related

How to pass custom comparator into priority queue constructor inline within map constructor in C++? [duplicate]

I have created a priority_queue with custom comparator which stores string in lexicographically sorted order, and it works as expected.[ Ref. this] ]
Now, I want it to be value in an unordered_map, and I got error: no matching constructor for initialization ... and closest thing I found is this. I realize I need to pass the comparator to the constructor as well, but how?
Here is my code as of now :
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std; // Used to make code less verbose
int main() {
auto cmp = [](string s1, string s2){
return s1.compare(s2) > 0;
};
using myQuque = priority_queue<string, vector<string>, decltype(cmp)> ;
// This code works
myQuque pq(cmp);
pq.push("ZZ");
pq.push("AA");
pq.push("CC");
while(!pq.empty()){
cout << pq.top() << " ";
pq.pop();
}
// This doesn't. How do I pass 'cmp' to constructor?
unordered_map<string, myQuque> table;
auto p = table["r"];
p.push("ZZ");
p.push("AA");
}
https://godbolt.org/z/cvPfPd
I then realized that I can use multiset as well for this application, but I still would like to know how can I use priority_queue with custom comparator in map.
Using a lambda was a bad idea... just provide comparison through the comparison template argument, then no constructor argument is required...
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std; // Used to make code less verbose
struct Cmp {
bool operator()(const string& s1, const string& s2) const {
return s1.compare(s2) > 0;
}
};
int main() {
using myQuque = priority_queue<string, vector<string>, Cmp>;
// This code works
myQuque pq;
pq.push("ZZ");
pq.push("AA");
pq.push("CC");
while(!pq.empty()){
cout << pq.top() << " ";
pq.pop();
}
// This doesn't. How do I pass 'cmp' to constructor?
unordered_map<string, myQuque> table;
auto p = table["r"];
p.push("ZZ");
p.push("AA");
}
Note too I've changed the comparison to take arguments by const reference, avoiding deep copying the text being compared for each comparison (at least whenever longer than any Short-String-Optimisation buffer your std::string implementation might have).
Maps use the default constructor when creating new elements. You could use pointers, but you’d need to allocate each new entry:
unordered_map<string, shared_ptr<myQuque>> table;
auto p = make_shared<myQueue>(cmp);
table["r"] = p;
p->push("ZZ");
p->push("AA");
Problem is that with custom run-time comparator, default constructor of myQuque is not available.
std::unordered_map::operator[] must be able to use default constructs for value in case there is no value ready for specyfic key. This is needed since it returns a reference to value which can be used in assignment expression.
To fix it you have to drop operator[], you can use this:
unordered_map<string, myQuque> table;
auto &p = table.emplace("r", cmp).first->second;
p.push("ZZ");
p.push("AA");
demo: https://godbolt.org/z/bPnrEe
As an alternative you can provide static comparator to priority_queue as Tony Delroys answer. In such case myQuque will have default constructor and problem vanishes.

find inside a class if an element exists within a vector of pairs

I'm coding in C++. I have a project with so many files. I have a vector of pairs named list as follows:
std::vector< std::pair< structure1, double> > list;
and I want to check if for a specific double value z , there exists an element: el in the list such that: el.second == z
I want to use find_if
To do so , I've implemented a method : Scheduled that takes two arguments: the first one is an element like those stored in the list , the second one is the specific value to look for.
I tried several ways but I end up getting an error always
1st way:
bool classA::Scheduled(std::pair< structure1,double > const el, double const t )
{
return el.second==t;
}
inside another method but still in the same class: classA
auto Scheduled1 = std::bind(&classA::Scheduled,this,_1,z);
bool call=std::find_if(list.begin(),list.end(),Scheduled1)=!list.end();
This solution gives the following error:
error: ‘Scheduled1’ does not name a type
2nd way:
directly using lambda
bool call = std::find_if(list.begin(),list.end(),[this](std::pair<struct1,double> const& el){return el.second==z;})!=list.end();
z is a member variable of classA
This second way of coding gives rise to this error:
error: no matching function for call to
‘find_if(std::vector >::iterator, std::vector >::iterator, classA::method1(int)::__lambda0)’
There's no need to mix bind, bind1st and mem_fun to do this (the latter two are deprecated in C++11); just use a lambda
bool call = std::find_if(list.begin(), list.end(),
[this](std::pair< strucure1,double > const& el) {
return el.second == z;
}) != list.end();
Or if you want to call Scheduled
bool call = std::find_if(list.begin(), list.end(),
[this](std::pair< strucure1,double > const& el) {
return Scheduled(el, z);
}) != list.end();
If you must use bind
bool call = std::find_if(list.begin(), list.end(),
std::bind(&classA::Scheduled, this, _1, z)) != list.end();
In either case, you might want to change Scheduled to be a static member function since it doesn't need access to any non-static members, in which case the bind option becomes
bool call = std::find_if(list.begin(), list.end(),
std::bind(&classA::Scheduled, _1, z)) != list.end();
Also, Scheduled should probably take the std::pair argument by const& to avoid unnecessary copies.
Another option is to use any_of instead of find_if, which avoids having to compare the result with the end interator
bool call = std::any_of(list.begin(), list.end(),
<insert lambda or bind expression>);
Here's an explanation of what's wrong with your attempt.
auto Scheduled1=std::bind(Scheduled, _1, z);
Scheduled is a non-static member function, which means it takes an implicit first argument, a pointer to the instance it must be invoked on, i.e. the this pointer. Moreover, the syntax for creating a pointer to member function is &ClassName::MemberFunctionName. So the above line should be
auto Scheduled1=std::bind(&classA::Scheduled, this, _1, z);
bind returns a function object of unspecified type, but you use that object as if it were a member function (mem_fun(&classA::Scheduled1)) which is clearly incorrect. Simply passing the above Scheduled1 object as the 3rd argument to find_if in your example should work.
As mentioned by #Praetorian, you could've used lambdas. However, binders allow one to use existing predicate functions out of the box, though, and is sometimes more readable (The fact that the new std::bind automatically binds a member function to instance, allows one to use the public interface of a type out of the box). I've added an example similar to yours (that compiles) in which I'll explain some things (see code comments):
#include <iostream>
#include <vector>
#include <utility>
#include <functional>
#include <algorithm>
// Replaces your structure...
struct Xs{};
// typedef so that we can alias the ugly thing...
typedef std::vector<std::pair<Xs, double>> XDoubleVector;
// --- From your code, I've just named it A for brevity....
struct A
{
bool Scheduled(std::pair<Xs,double> const el, double const t )
{
return el.second==t;
}
};
int main() {
using namespace std::placeholders;
//Instantiate it.... replaced your list.
XDoubleVector doubleVect;
//--- and add some elements....
//We need to instantiate A, in order to invoke
// a member function...
A a;
// Returns true if found...
return std::find_if(
doubleVect.begin(),
doubleVect.end(),
//Notes:
//- Scheduled is a member function of A
//- For that reason, we need to pass an instance of
// A to binder (almost seen as first bound).
//- _1 indicates that the first parameter to Scheduled will be
// passed in by algorithm
//- We've hardcoded the second parameter (it is therefore
// bound early).
std::bind(&A::Scheduled, a, _1, 20.9)) != doubleVect.end();
}
Regards, Werner

Error inserting custom class to map as value

I'm having trouble understanding why this isn't working as I expect it to. It may be that I'm using Visual Studio 2013, but hey.
This code is part of the item randomization system in a game engine I'm writing.
// the chance a rarity will have a given number of affixes
std::unordered_map<ItemRarities, ChanceSelector<int>> affixCountChances = {
std::pair<ItemRarities, ChanceSelector<int>>(ItemRarities::Cracked,
{ ChanceSelector<int>(
{ ChancePair(int, 100, 0) }) }),
std::pair<ItemRarities, ChanceSelector<int>>(ItemRarities::Normal,
{ ChanceSelector<int>(
{ ChancePair(int, 80, 0),
ChancePair(int, 20, 1) }) }),
// snip for conciseness (there are 3 more)
};
And this is the ChanceSelector class:
using Percentage = int;
#define ChancePair(T, p, v) std::pair<Percentage, T>(p, v)
template <class T>
class ChanceSelector
{
private:
std::unordered_map<T, Percentage> _stuff;
public:
ChanceSelector()
{
}
~ChanceSelector()
{
if (_stuff.size() > 0)
_stuff.clear();
}
ChanceSelector(std::initializer_list<std::pair<Percentage, T>> list)
{
// snip for conciseness
}
T Choose()
{
// snip for conciseness
}
};
The above code compiles fine but I have two questions:
I don't understand why using ChanceSelector in std::pair requires a default constructor. Explicitly, it looks like I'm calling the constructor with the initializer list.
When the applications runs, it crashes with: Unhandled exception at 0x01762fec in (my
executable): 0xC0000005: Access violation reading location 0xfeeefeee.
Number 2 goes away if I only have one item in that map or if I change the definition of affixCountChances to std::unordered_map<ItemRarities, ChanceSelector<int>*> (and adjust the rest accordingly). The error dumps me at this code in list:
for (_Nodeptr _Pnext; _Pnode != this->_Myhead; _Pnode = _Pnext)
{
_Pnext = this->_Nextnode(_Pnode); // <-- this line
this->_Freenode(_Pnode);
}
Further inspection reveals the error happened in the destructor. _stuff is empty:
~ChanceSelector()
{
if (_stuff.size() > 0)
_stuff.clear();
}
It is legitly calling the destructor. Items are being removed from _stuff but I don't see why it would be calling the destructor. The crash happens after all items have been constructed and affixCountChances contains all items. I would assume that means it's destroying all the temporaries it created but I don't see why it would be creating temporaries.
Edit:
Constructor of ChanceSelector:
ChanceSelector(std::initializer_list<std::pair<Percentage, T>> list)
{
int total = 0;
int last = 100;
for (auto& item : list)
{
last = item.first;
total += item.first;
_stuff[item.second] = total;
}
// total must equal 100 so that Choose always picks something
assert(total == 100);
}
To answer your two questions:
std::pair requires a default constructor, because you can do something like
std::pair<int, MyClass> myPair();
which creates a copy of your class using the default constructor (The values of the pair are actual values and not references):
// MSVC implementation
template<class _Ty1,class _Ty2>
struct pair
{ // store a pair of values
typedef pair<_Ty1, _Ty2> _Myt;
typedef _Ty1 first_type;
typedef _Ty2 second_type;
pair()
: first(), second() // Here your class gets default constructed
{ // default construct
}
// .....
_Ty1 first; // the first stored value
_Ty2 second; // the second stored value
};
The template of the pair gets fully implemented, so you need a default constructor event if you are not using the line above.
One way to avoid this dependency is to use pointers in the std::pair, this then sets the default value of the second value of the pair to nullptr:
std::pair<int, MyClass*> myPair();
0xFEEEFEEE indicates that the storage, where your pointer itself was stored has already been deleted (e.g. working on a deleted class reference).
This deletion seems to occur somewhere outside the code you have posted here.
For more Magic Numbers see Magic Numbers on Wikipedia
Edit:
Additionally, the contents of the initializer list do not exist after the constructor call. You might have there a reference copied instead of the actual object, which then gets deleted. The msvc implementation of the std::unordered_map uses a std::list as base for storing items. I'm not able to give your more information about this with the given code.
Initializer list and lifetime of its content
Edit 2: I was able to reproduce the error with your given code, it was not the content of the initializer_list ctor.
The problem seems to be the lifetime of the objects inside the initializer list.
When I move the declaration of the pairs for the unordered map out of the initializer_list for the unordered map, everything works fine:
std::pair<ItemRarities, ChanceSelector<int>> pair1( ItemRarities::Cracked,
{ ChanceSelector<int>(
{ ChancePair( int, 100, 0 ) } ) } );
std::pair<ItemRarities, ChanceSelector<int>> pair2( ItemRarities::Normal,
{ ChanceSelector<int>(
{ ChancePair( int, 80, 0 ),
ChancePair( int, 20, 1 ) } ) } );
std::unordered_map<ItemRarities, ChanceSelector<int>> chances = {
pair1,
pair2
};
I'm not completely sure why this is a problem, but I think is comes from the {} in the initializer list, those objects might get deleted, when leaving the first {} and before entering the actual intializer_list for the unordered_map

Get Element Position within std::vector

How do I get the position of an element inside a vector, where the elements are classes. Is there a way of doing this?
Example code:
class Object
{
public:
void Destroy()
{
// run some code to get remove self from vector
}
}
In main.cpp:
std::vector<Object> objects;
objects.push_back( <some instances of Object> );
// Some more code pushing back some more stuff
int n = 20;
objects.at(n).Destroy(); // Assuming I pushed back 20 items or more
So I guess I want to be able to write a method or something which is a member of the class which will return the location of itself inside the vector... Is this possible?
EDIT:
Due to confusion, I should explain better.
void Destroy(std::vector<Object>& container){
container.erase( ?...? );
}
The problem is, how can I find the number to do the erasing...? Apparently this isn't possible... I thought it might not be...
You can use std::find to find elements in vector (providing you implement a comparison operator (==) for Object. However, 2 big concerns:
If you need to find elements in a container then you will ger much better performance with using an ordered container such as std::map or std::set (find operations in O(log(N)) vs O(N)
Object should not be the one responsible of removing itself from the container. Object shouldn't know or be concerned with where it is, as that breaks encapsulation. Instead, the owner of the container should concern itself ith such tasks.
The object can erase itself thusly:
void Destroy(std::vector<Object>& container);
{
container.erase(container.begin() + (this - &container[0]));
}
This will work as you expect, but it strikes me as exceptionally bad design. Members should not have knowledge of their containers. They should exist (from their own perspective) in an unidentifiable limbo. Creation and destruction should be left to their creator.
Objects in a vector don't automatically know where they are in the vector.
You could supply each object with that information, but much easier: remove the object from the vector. Its destructor is then run automatically.
Then the objects can be used also in other containers.
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class object_t
{
private:
int id_;
public:
int id() const { return id_; }
~object_t() {}
explicit object_t( int const id ): id_( id ) {}
};
int main()
{
using namespace std;
vector<object_t> objects;
for( int i = 0; i <= 33; ++i )
{
objects.emplace_back( i );
}
int const n = 20;
objects.erase( objects.begin() + n );
for( auto const& o : objects )
{
cout << o.id() << ' ';
}
cout << endl;
}
If you need to destroy the n'th item in a vector then the easiest way is to get an iterator from the beginning using std::begin() and call std::advance() to advance how ever many places you want, so something like:
std::vector<Object> objects;
const size_t n = 20;
auto erase_iter = std::advance(std::begin(objects), n);
objects.erase(erase_iter);
If you want to find the index of an item in a vector then use std::find to get the iterator and call std::distance from the beginning.
So something like:
Object object_to_find;
std::vector<Object> objects;
auto object_iter = std::find(std::begin(objects), std::end(objects), object_to_find);
const size_t n = std::distance(std::begin(objects), object_iter);
This does mean that you need to implement an equality operator for your object. Or you could try something like:
auto object_iter = std::find(std::begin(objects), std::end(objects),
[&object_to_find](const Object& object) -> bool { return &object_to_find == &object; });
Although for this to work the object_to_find needs to be the one from the actual list as it is just comparing addresses.

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.)