Say I have the following classes:
#include <string>
class Item {
public:
Item(std::string name, int id);
virtual int getWeight() = 0;
protected:
std::string name;
const int id;
}
#include <vector>
#include <memory>
#include "Item.h"
class Bucket : Item {
public:
Bucket(std::string name, std::string type, int id) // In the implementation this will call the Constructor of Item
bool operator<(const Bucket& b) const {
return (id < b.id );
}
void addItem(std::shared_ptr<Item> itemm) {
this->weight += item->getWeight();
this->items.push_back(item);
}
int getWeight() override; //this implementation does not matter to the problem
private:
std::string type;
std::vector<std::shared_ptr<Item>> items;
int weight = 0;
}
There are other classes inheriting from class Item aswell, but to make it easier I am only showing the class Bucket.
Now in my main method, I want to iterate over a map, that already contains some entries and call a method that changes one property of the key object.
main.cpp:
#include <map>
#include <memory>
#include <vector>
#include "Item.h"
#include "Bucket.h"
using namespace std;
int main(){
map<Bucket, vector<shared_ptr<Item>>> map; // Imagine this map has some entries
for(auto itr = map.begin(); itr != map.end(); itr++){
for_each(itr->second.begin(), itr->second.begin(), [&itr](shared_ptr<Item> item){
itr->first.addItem(item); // This does not compile, the error will be in the text below
});
}
As told in the code, it does not compile with the following error on line itr->first.addItem(item);:
'this' argument to member function 'addItem' has type 'const Bucket', but function is not marked const.
I can't make the method const, since it is changeing some property of the object and I would get an error there.
I am not sure if I understand this error correctly, but I think the problem is, that as I put a Bucket into a map (Bucket is the key), it becomes const.
If that is the case, is there a way to tell the compiler to use only the id property of Bucket as the const key of the map (Without changeing the map to something like map<int, <pair<Bucket,vector<shared_ptr<Item>>>>>)? Or am I not understanding the main problem here?
I think the problem is, that as I put a Bucket into a map (Bucket is the key), it becomes const
Correct. Maps are supposed to be ordered, and if you were able to mutate a key, you could break this invariant. Doing this would potentially break every subsequent search or insert horribly.
The linked workaround is effective, but ugly. Unless map-key-ness is a core feature of your Bucket (I can't tell from the sample code whether that's likely), making some of its members mutable feels like a hack.
Your whole design looks odd, tbh - you're going to end up with a map full of Bucket keys that duplicate the information in the second half of the key,value pair. Are you going to move those Buckets somewhere else afterwards, or are they going to live forever shackled to those vestigial vectors of redundant references?
If that map is an intermediate step in building up connections, it shouldn't be where the Bucket objects live. Perhaps you should have one main lookup map<id, Item>, another transient mapping multimap<id, id> describing which Item contains which other Items.
Related
I am trying to sort a vector that contains custom struct entries using a lambda function in c++ . But I get prompted the following error message
error: use of deleted function ‘dummy_struct& dummy_struct::operator=(const dummy_struct&)
The code looks like the following:
#include <regex>
struct dummy_struct
{
dummy_struct(std::string name, int64_t value_a) :
name(name),
value_a(value_a)
{}
const std::string name;
const int64_t value_a;
int ExtractNumberFromName(std::regex key)
{
int retval;
std::cmatch match;
std::regex_search(this->name.c_str(),match,key);
retval=std::stoi(match[0],nullptr);
return retval;
}
};
void SortByCustomKey(const std::vector<dummy_struct> collection, std::regex key)
{
auto compare = [key](dummy_struct a, dummy_struct b)
{
return a.ExtractNumberFromName(key) > b.ExtractNumberFromName(key)
};
std::sort(std::begin(collection),std::end(collection),compare);
}
int main()
{
std::vector<dummy_struct> test;
test.push_back(dummy_struct("Entry[1]",1));
test.push_back(dummy_struct("Entry[2]",2));
test.push_back(dummy_struct("Entry[3]",3));
SortByCustomKey(test,std::regex("[0-9]+"));
}
What am I missing here?
std::sort sorts vector by swapping it's elements in place.
This requires for your class to implement copy assignment operator (or move assignment), which compiler won't generate for you due to const fields in the class. For your example the only solution seems to remove the const qualifiers from the fields. If you don't want them to be modified just make them private and don't provide (public) setters.
If they absolutely must stay there and you just want to get your values in sorted order you can use a different structure or store pointers in the vector.
Another solution is to write a custom swap implementation for your class that would const_cast away the qualifiers of the fields for the purpose of the assignment, although this is usually a bad code smell.
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.
I have several GUIDs and I'd like to implement a hash table to quickly retrieve them. How would I do that?
If I treat the GUIDs as hash codes I need to do something like
index = GUID % prime_number_that_covers_all_GUID_bits
but I'm unsure if this is the right way to do it. How should I do to realize such a hash table?
You could use std::unordered_map, which takes a Key type (GUID) in your case, and a Value type, which could be some user info or program info (depending on your app). Storing is as simple as calling the member functions insert() or emplace() and looking up a stored value is done by calling find().
The example below uses std::string as the underlying type for your keys, and implicitly std::hash<std::string> as the hash function. For other GUID types, you might need to roll your own hash function object and pass that as a template parameter to the hash table.
#include <iostream>
#include <ios>
#include <string>
#include <unordered_map>
typedef std::string GUID;
class UserInfo
{
public:
UserInfo(bool b): is_genius_(b) {}
bool is_genius() const { return is_genius_; }
private:
bool is_genius_;
// your stuff here
};
int main()
{
std::unordered_map<GUID, UserInfo> table;
GUID x = "Johnny Pauling";
// insert into table
table.emplace(x, UserInfo(true));
// lookup in table
auto it = table.find(x);
// if found, print it
if (it != table.end())
std::cout << std::boolalpha << it->second.is_genius();
}
Output on LiveWorkSpace
Consider the following class member:
std::vector<sim_mob::Lane *> IncomingLanes_;
the above container shall store the pointer to some if my Lane objects. I don't want the subroutins using this variable as argument, to be able to modify Lane objects.
At the same time, I don't know where to put 'const' keyword that does not stop me from populating the container.
could you please help me with this?
thank you and regards
vahid
Edit:
Based on the answers i got so far(Many Thanks to them all) Suppose this sample:
#include <vector>
#include<iostream>
using namespace std;
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_)
{
a=a_;
}
void printLane()
{
std::cout << a << std::endl;
}
};
class B
{
public:
vector< Lane const *> IncomingLanes;
void addLane(Lane *l)
{
IncomingLanes.push_back(l);
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(&l1);
b.addLane(&l2);
b.IncomingLanes.at(1)->printLane();
b.IncomingLanes.at(1)->setA(12);
return 1;
}
What I meant was:
b.IncomingLanes.at(1)->printLane()
should work on IncomingLanes with no problem AND
b.IncomingLanes.at(1)->setA(12)
should not be allowed.(In th above example none of the two mentioned methods work!)
Beside solving the problem, I am loking for good programming practice also. So if you think there is a solution to the above problem but in a bad way, plase let us all know.
Thaks agian
A detour first: Use a smart pointer such shared_ptr and not raw pointers within your container. This would make your life a lot easy down the line.
Typically, what you are looking for is called design-const i.e. functions which do not modify their arguments. This, you achieve, by passing arguments via const-reference. Also, if it is a member function make the function const (i.e. this becomes const within the scope of this function and thus you cannot use this to write to the members).
Without knowing more about your class it would be difficult to advise you to use a container of const-references to lanes. That would make inserting lane objects difficult -- a one-time affair, possible only via initializer lists in the ctor(s).
A few must reads:
The whole of FAQ 18
Sutter on const-correctness
Edit: code sample:
#include <vector>
#include <iostream>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
#include <vector>
#include <iostream>
#include <memory>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_) // do you need this?
{
a=a_;
}
void printLane() const // design-const
{
std::cout << a << std::endl;
}
};
class B
{
// be consistent with namespace qualification
std::vector< Lane const * > IncomingLanes; // don't expose impl. details
public:
void addLane(Lane const& l) // who's responsible for freeing `l'?
{
IncomingLanes.push_back(&l); // would change
}
void printLane(size_t index) const
{
#ifdef _DEBUG
IncomingLanes.at( index )->printLane();
#else
IncomingLanes[ index ]->printLane();
#endif
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
//b.IncomingLanes.at(1)->printLane(); // this is bad
//b.IncomingLanes.at(1)->setA(12); // this is bad
b.printLane(1);
return 1;
}
Also, as Matthieu M. suggested:
shared ownership is more complicated because it becomes difficult to
tell who really owns the object and when it will be released (and
that's on top of the performance overhead). So unique_ptr should be
the default choice, and shared_ptr a last resort.
Note that unique_ptrs may require you to move them using std::move. I am updating the example to use pointer to const Lane (a simpler interface to get started with).
You can do it this way:
std::vector<const sim_mob::Lane *> IncomingLanes_;
Or this way:
std::vector<sim_mob::Lane const *> IncomingLanes_;
In C/C++, const typename * and typename const * are identical in meaning.
Updated to address updated question:
If really all you need to do is
b.IncomingLanes.at(1)->printLane()
then you just have to declare printLane like this:
void printLane() const // Tell compiler that printLane doesn't change this
{
std::cout << a << std::endl;
}
I suspect that you want the object to be able to modify the elements (i.e., you don't want the elements to truly be const). Instead, you want nonmember functions to only get read-only access to the std::vector (i.e., you want to prohibit changes from outside the object).
As such, I wouldn't put const anywhere on IncomingLanes_. Instead, I would expose IncomingLanes_ as a pair of std::vector<sim_mob::Lane *>::const_iterators (through methods called something like GetIncomingLanesBegin() and GetIncomingLanesEnd()).
you may declare it like:
std::vector<const sim_mob::Lane *> IncomingLanes_;
you will be able to add, or remove item from array, but you want be able to change item see bellow
IncomingLanes_.push_back(someLine); // Ok
IncomingLanes_[0] = someLine; //error
IncomingLanes_[0]->some_meber = someting; //error
IncomingLanes_.erase(IncomingLanes_.end()); //OK
IncomingLanes_[0]->nonConstMethod(); //error
If you don't want other routines to modify IncomingLanes, but you do want to be able to modify it yourself, just use const in the function declarations that you call.
Or if you don't have control over the functions, when they're external, don't give them access to IncomingLanes directly. Make IncomingLanes private and provide a const getter for it.
I don't think what you want is possible without making the pointers stored in the vector const as well.
const std::vector<sim_mob::Lane*> // means the vector is const, not the pointer within it
std::vector<const sim_mob::Lane*> // means no one can modify the data pointed at.
At best, the second version does what you want but you will have this construct throughout your code where ever you do want to modify the data:
const_cast<sim_mob::Lane*>(theVector[i])->non_const_method();
Have you considered a different class hierarchy where sim_mob::Lane's public interface is const and sim_mob::Really_Lane contains the non-const interfaces. Then users of the vector cannot be sure a "Lane" object is "real" without using dynamic_cast?
Before we get to const goodness, you should first use encapsulation.
Do not expose the vector to the external world, and it will become much easier.
A weak (*) encapsulation here is sufficient:
class B {
public:
std::vector<Lane> const& getIncomingLanes() const { return incomingLanes; }
void addLane(Lane l) { incomlingLanes.push_back(l); }
private:
std::vector<Lane> incomingLanes;
};
The above is simplissime, and yet achieves the goal:
clients of the class cannot modify the vector itself
clients of the class cannot modify the vector content (Lane instances)
and of course, the class can access the vector content fully and modify it at will.
Your new main routine becomes:
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
b.getIncomingLanes().at(1).printLane();
b.getIncomingLanes().at(1).setA(12); // expected-error\
// { passing ‘const Lane’ as ‘this’ argument of
// ‘void Lane::setA(int)’ discards qualifiers }
return 1;
}
(*) This is weak in the sense that even though the attribute itself is not exposed, because we give a reference to it to the external world in practice clients are not really shielded.
Q#1) Struct below doesn't want to be copied and gives compilation errors - why and how to deal with it?
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct person
{
person(string n)
:name(n)
{}
string name;
};
int main()
{
map<string, person> my_map;
my_map["one"] = person("Tom");
return 0;
}
Q#2) We can avoid the problem above by omitting the struct constructor "person(const string& n)" and assigning struct values one by one:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct person
{
string name;
};
int main()
{
map<string, person> my_map;
person p;
p.name = "Tom";
my_map["one"] = p;
return 0;
}
So, let's say I do it this way, and after storing many persons in the map I want to check if a particular person exists inside a map. As I know the correct way of doing it is:
if(my_map.find("one") == my_map.end()) { //it doesn't exist in my_map }
else {//it exists}
But this as I understand will iterate through the whole map one by one, won't it? If yes, then is it okay to do it like:
using namespace std;
struct person
{
string name;
string identifier; // <--
};
int main()
{
map<string, person> my_map;
person p;
p.name = "Tom";
p.identifier = "something"; // <--
my_map["one"] = p;
if(my_map["unknown"].identifier == "something") // <--
cout << "Found" << endl;
else
cout << "Not found" << endl;
return 0;
}
By doing this we avoid iterating, and possibility that garbage in the memory will match our identifier is... small I guess, especially if we use some hash.
So is it okay (secure) doing like that?
1) The code in your first example fails to compile because of the following expression:
my_map["one"]
my_map["one"] constructs a std::string from "one", and passes it to std::map::operator[]. map::operator[] ensures that a value is mapped to the supplied key (by associating the key with a default-constructed value if it is not already associated with a value) and returns a reference to that value.
This does not compile, because person does not have a default constructor (A "default constructor" is a constructor which takes no arguments).
There are several ways to fix this problem.
One way is the way that you took - removing the constructor. It works because if you do not supply any constructors, a default constructor will be implicitly defined.
Another way is to explicitly define a default constructor for person:
struct person
{
person():name(){} //or person()=default; if your compiler supports this
person(string n)
:name(n)
{}
string name;
};
Another way is to not use operator[] at all, and to instead use map::insert, as follows:
auto pair(my_map.insert(std::make_pair(std::string("one"),person("Tom"))));
if (!pair.second) {
*pair.first = person("Tom");
}
2) The correct way to find an element in the map is (as you said) to use:
if(my_map.find("one") == my_map.end()) {/*it doesn't exist in my_map*/}
else {/*it exists*/}
This does not inspect every element in the map - in fact it may only inspect O(log(map.size())) elements.
Your fears are totally unfounded, this is the correct way to find an element in the map, however the way in which you continue suggests a severe misunderstanding about what operator[] does.
You ask "what is the probability that my_map["unknown"].identifier == "something" will return true if "unknown" does not exist in the map?".
The answer to this is that there is no chance whatsoever of this returning true, because if no value with the key std::string("unknown") exists in the map, then operator[] will associate std::string("unknown") with a default constructed person, and so identifier will be an empty string.
First of all, since you have a constructor, you need to provide a default constructor. This is because C++ standard library containers use value semantics. So the map needs to be able to copy values, assign them, and default construct them. Since you provide a constructor, the compiler does not synthesize the default constructor. This is a default constructor that does nothing:
person() {} // default constructs string, so no special aciton required.
Particularly in the case of std::map, operator[] returns a reference to a default constructed value when an element with the key does not already exist in the map:
my_map["one"] = p; // creates *default* person, then *assigns* it the value of p.
Second, concerning your question about searching the map, std::map, search has logarithmic complexity and is typically implemented as a self-balancing binary tree. So when you search you do not traverse the whole map. And since accessing via operator[] introduces new elements when the searched key doesn't exist, the form using find() is the canonical way to do it.
Since you mentioned hashing, C++11 provides std::unordered_map, and tr1 and boost have hash_map. These use hash functions perform the search is constant time. Whether it is worth using it or not depends on factors such as the size of your map. The constant time could be larger than the logarithmic time taken to search a small map.
Note:
If you want to use your struct as key, or want to insert it into one of the standard library sets, you have further requirements:
maps: You need to provide strict weak ordering, for the key, either via a less-than operator for your class, or a custom comparator functor. If you were to use person as a key, you woul dneed something like:
bool operator<(const person& rhs) const { return name < rhs.name; }
unordered_ or hash maps: You must provide both a hash function and an equality comparison for the key, either via an operator== or a functor. .