Suppose the following:
struct C {
... // lots of other stuff
int get(int key) const { return m.at(key); } // This will never throw
private:
std::unordered_map<int, int> m;
};
Due to how the application works, I know that get never throws. I want to make get as fast as possible. So, I would like to make the access unchecked, i.e. I would like to write something like return m[key]. Of course, I cannot write exactly that while keeping get const. However, I want to keep get const, since it is logically const.
Here is the only (ugly) solution I came up with:
struct C {
... // lots of other stuff
int get(int key) const { return const_cast<C *>(this)->m[key]; }
private:
std::unordered_map<int, int> m;
};
Is there a better way?
One approach would be to use std::unordered_map::find:
struct C {
... // lots of other stuff
int get(int key) const { return m.find(key)->second; }
private:
std::unordered_map<int, int> m;
};
I object to the very reasoning behind this question. The overhead (of map.at() vs map[]) associated with catching an error due to unknown key is presumably tiny compared to the cost of finding the key in the first place.
Yet, you willingly take the serious risk of a run-time error just for such a marginal efficiency advantage that you presumably have not even validated/measured. You may think that you know that key is always contained in the map, but perhaps future code changes (including bugs introduced by others) may change that?
If you really know, then you should use
map.find(key)->second;
which makes the bug explicit if the iterator returned is invalid (i.e. equal to map.end()). You may use assert in pre-production code, i.e.
auto it = map.find(key);
assert(it!=map.end());
return it->second;
which in production code (when assert is an empty macro) is removed.
Related
Suppose I have some object with an initial name such as quantities_of_widgets.
std::vector<int> quantities_of_widgets = GetQuantities();
I then perform an operation on quantities_of_widgets in-place. The vector quantities_of_widgets no longer represents "a vector of some quantities of things called widgets".
PerformOperationInPlace(quantities_of_widgets);
After this operation, a more appropriate name for the variable would be weights_of_widgets. That would certainly make the code more readable.
I can "change" the name by moving quantities_of_widgets to a new vector weights_of_widgets. This is a terrible idea. The move isn't free, it messes with memory continuity, etc.
std::vector<int> weights_of_widgets = std::move(quantities_of_widgets);
I could also document the meaning of the variable in comments. I might write
std::vector<int> widgets = GetQuantities(); // widgets represents quantities
PerformOperationInPlace(widgets); // widgets represents weights
UseWeights(widgets);
However, comments are less permanent and less readable. It becomes more difficult to keep track of the meaning of variables over multiple lines of code. If widgets is used 20 lines down in the middle of a large expression, I'd have trouble documenting the meaning of the variable at that point.
SomeBigFunction(Func1(widgets, some_other_object_1), some_other_object_2);
I could try aliasing, but I want to make the old name invalid to help with maintainability. Is there a way to change the name of a variable with no run-time cost?
Worrying about such small overhead is almost certainly not worth the effort in all but the most extreme scenarios. However, for the sake of completeness:
The only way to get truly overhead-free renaming of types with non-trivial destructors is via copy-elision.
In this context, you could make use of it via an immediately evaluated lambda and NRVO.
#include <vector>
std::vector<int> GetQuantities(int v);
void PerformOperationInPlace(std::vector<int>&);
void UseWeights(const std::vector<int>&);
template<typename T>
T rename(T&& rhs) {
return rhs;
}
void foo(int x) {
std::vector<int> quantities_of_widgets = GetQuantities(x);
PerformOperationInPlace(quantities_of_widgets);
UseWeights(quantities_of_widgets);
}
void bar(int x) {
std::vector<int> weights_of_widgets = [&]{
std::vector<int> quantities_of_widgets = GetQuantities(x);
PerformOperationInPlace(quantities_of_widgets);
return quantities_of_widgets;
}();
UseWeights(weights_of_widgets);
}
foo() and bar() compile down to effectively the exact same final assembly: (see on godbolt)
The only limitation is that the variable that will be renamed has to be declared within the lambda. Beyond that, implicit capture by reference makes the lambda effectively the same thing as a scope.
It is best to document code by itself. Comments have tendency do degrade.
So I would do this this way:
// name of this function terrible, it should be more like
// ExtractWeightsOfWidgetsFrom or something similar
std::vector<int> OperationInPlace(std::vector<int> data) {
// note argument is a copy!
....
return data;
}
void someCode() {
auto quantities_of_widgets = GetQuantities();
...
auto weights_of_widgets = PerformOperationInPlace(std::move(quantities_of_widgets));
// here `quantities_of_widgets` is empty since contents has been moved
// many tools will report an error if you use this value after that point
....
}
or even better I would just extract more functions:
void someCode() {
auto quantities_of_widgets = GetQuantities();
...
ProcesWeightsOfWidgets(
PerformOperationInPlace(std::move(quantities_of_widgets));
// in this version someCode ends here
}
Given the following:
class ReadWrite {
public:
int Read(size_t address);
void Write(size_t address, int val);
private:
std::map<size_t, int> db;
}
In read function when accessing an address which no previous write was made to I want to either throw exception designating such error or allow that and return 0, in other words I would like to either use std::map<size_t, int>::operator[]() or std::map<size_t, int>::at(), depending on some bool value which user can set. So I add the following:
class ReadWrite {
public:
int Read(size_t add) { if (allow) return db[add]; return db.at(add);}
void Write(size_t add, int val) { db[add] = val; }
void Allow() { allow = true; }
private:
bool allow = false;
std::map<size_t, int> db;
}
The problem with that is:
Usually, the program will have one call of allow or none at the beginning of the program and then afterwards many accesses. So, performance wise, this code is bad because it every-time performs the check if (allow) where usually it's either always true or always false.
So how would you solve such problem?
Edit:
While the described use case (one or none Allow() at first) of this class is very likely it's not definite and so I must allow user call Allow() dynamically.
Another Edit:
Solutions which use function pointer: What about the performance overhead incurred by using function pointer which is not able to make inline by the compiler? If we use std::function instead will that solve the issue?
Usually, the program will have one call of allow or none at the
beginning of the program and then afterwards many accesses. So,
performance wise, this code is bad because it every-time performs the
check if (allow) where usually it's either always true or always
false. So how would you solve such problem?
I won't, The CPU will.
the Branch Prediction will figure out that the answer is most likely to be same for some long time so it will able to optimize the branch in the hardware level very much. it will still incur some overhead, but very negligible.
If you really need to optimize your program, I think your better use std::unordered_map instead of std::map, or move to some faster map implementation, like google::dense_hash_map. the branch is insignificant compared to map-lookup.
If you want to decrease the time-cost, you have to increase the memory-cost. Accepting that, you can do this with a function pointer. Below is my answer:
class ReadWrite {
public:
void Write(size_t add, int val) { db[add] = val; }
// when allowed, make the function pointer point to read2
void Allow() { Read = &ReadWrite::read2;}
//function pointer that points to read1 by default
int (ReadWrite::*Read)(size_t) = &ReadWrite::read1;
private:
int read1(size_t add){return db.at(add);}
int read2(size_t add) {return db[add];}
std::map<size_t, int> db;
};
The function pointer can be called as the other member functions. As an example:
ReadWrite rwObject;
//some code here
//...
rwObject.Read(5); //use of function pointer
//
Note that non-static data member initialization is available with c++11, so the int (ReadWrite::*Read)(size_t) = &ReadWrite::read1; may not compile with older versions. In that case, you have to explicitly declare one constructor, where the initialization of the function pointer can be done.
You can use a pointer to function.
class ReadWrite {
public:
void Write(size_t add, int val) { db[add] = val; }
int Read(size_t add) { (this->*Rfunc)(add); }
void Allow() { Rfunc = &ReadWrite::Read2; }
private:
std::map<size_t, int> db;
int Read1(size_t add) { return db.at(add); }
int Read2(size_t add) { return db[add]; }
int (ReadWrite::*Rfunc)(size_t) = &ReadWrite::Read1;
}
If you want runtime dynamic behaviour you'll have to pay for it at runtime (at the point you want your logic to behave dynamically).
You want different behaviour at the point where you call Read depending on a runtime condition and you'll have to check that condition.
No matter whether your overhad is a function pointer call or a branch, you'll find a jump or call to different places in your program depending on allow at the point Read is called by the client code.
Note: Profile and fix real bottlenecks - not suspected ones. (You'll learn more if you profile by either having your suspicion confirmed or by finding out why your assumption about the performance was wrong.)
[UPDATE: My problem is solved! Lots of thanks to Mike Seymour and Niall and all you guys!]
My code has errors in the for loop and I do not know how to fix it :(
MyClass::ITECH7603Class(set<Student>* students) {
/* Initialize dynamically the group field */
group = new map<string, Student>();
for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
addStudent(it);
}
}
void MyClass::addStudent(Student* studentPtr) {
string fullName = studentPtr->getName() + " " + studentPtr->getSurname();
group->insert(pair<string, Student>(fullName, *studentPtr));
}
So the main idea is to loop through all students in the set, and add each student into a map group. Any help? Thank you very much!
for (set<Student>::iterator it = students->begin; it != students->end; it++) {
addStudent(it);
}
should be:
for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
//^^ //^^
addStudent(it);
}
addStudent takes a pointer, while it is an iterator, so can't be passed directly.
You should change addStudent to take either a value or a pointer/reference to const:
// option 1
void addStudent(Student);
addStudent(*it);
// option 2
void addStudent(Student const &);
addStudent(*it);
// option 3
void addStudent(Student const *);
addStudent(&*it);
If, as you say in a comment, you must leave it taking a mutable pointer, then you'll need some grotesquery to deal with the fact that elements of the set are immutable:
// nasty option
addStudent(const_cast<Student*>(&*it));
// slightly less nasty option
Student copy = *it;
addStudent(©);
Beware that the first option will give undefined behaviour if the function uses the dodgy pointer to make any modification to the Student object stored in the set. The second makes a temporary copy, which can be modified without breaking the set. This is fine as long as addStudent only stores a copy of the object passed to it, not the pointer itself, which will become invalid when copy is destroyed.
In c++11 you can use range for sytax:
for (const auto &student : *students)
{
addStudent(it);
}
Then change addStudent function signature to accept reference:
void MyClass::addStudent(const Student &student) {
While you've gotten answers that "fix" your code to the extent of compiling and producing results that you apparently find acceptable, I don't find them very satisfying in terms of code style. I would do this job rather differently. In particular, my code to do this wouldn't have a single (explicit) loop. If I needed to do approximately what you're asking for, I'd probably use code something like this:
std::pair<std::string, Student> make_mappable(Student &stud) {
return std::make_pair(stud.getName() + " " + stud.getSurName(), stud);
}
std::map<std::string, Student> gen_map(std::set<Student> const &input) {
std::map<std::string, Student> ret;
std::transform(input.begin(), input.end(),
std::inserter(ret, ret.end()),
make_mappable);
return ret;
}
There definitely would not be any new in sight, nor would there be any passing a pointer to a Student.
OTOH, since the data you're using as the key for your map is data that's already in the items in the set, it may more convenient all around to continue to use a set, and just specify a comparison function based on the student's name:
struct by_given_name {
bool operator()(Student const &a, Student const &b) const {
if (a.getName() < b.getName())
return true;
if (b.getName() < a.getName())
return false;
return a.getSurName() < b.getSurName();
}
};
std::set<Student, by_given_name> xform(std::set<Student> const &in) {
return std::set<Student, by_given_name>{in.begin(), in.end()};
}
For what its worth, a Live Demo of the latter.
Whether the latter is practical will typically depend on one other factor though: your ability to create a Student from only a name/surname. If you can't do that, searching by name will be inconvenient (at best), so you'd want to use a map.
I realize this probably isn't much (if any) help in completely what's apparently home-work for a class--but even if your class prevents you from actually turning in decent code, it seems worthwhile to me to at least try to learn to write decent code in addition to what it requires. If you do pass the class and get a job writing code, you'd probably rather your coworkers didn't want to hurt you.
I was curious as to whether the following scenario is safe.
I have the following class definitions:
class ActiveStatusEffect
{
public:
StatusEffect* effect;
mutable int ReminaingTurns;
ActiveStatusEffect() : ReminaingTurns(0)
{
}
//Other unimportant stuff down here
}
I then store a group of these inside an std::set as follows:
struct ASECmp
{
bool operator ()(const StatusEffects::ActiveStatusEffect &eff1, const StatusEffects::ActiveStatusEffect &eff2)
{
return eff1.effect->GetPriority() < eff2.effect->GetPriority();
}
};
std::set<StatusEffects::ActiveStatusEffect, ASECmp> ActiveStatusEffects;
I mark RemainingTurns as mutable because I want to be able to change it without haing to constantly erase/insert into the set. I.e.
void BaseCharacter::Tick(Battles::BattleField &field, int ticks)
{
for (auto effect = ActiveStatusEffects.begin(); effect != ActiveStatusEffects.end();)// ++index)
{
auto next = effect;
++next;
if (effect->effect->HasFlag(StatusEffects::STATUS_FLAGS::TickEffect) && effect->ReminaingTurns > 0)
{
effect->effect->TickCharacter(*this, field, ticks);
--effect->ReminaingTurns;
}
if (effect->ReminaingTurns == 0)
{
ActiveStatusEffects.erase(effect);
}
effect = next;
}
}
I'm concerned because it seems possible for this to mess up the ordering within the set, meaning I can't guarantee the set will always be sorted by effect->GetPrority()
If that's true, is there a safe way (such as not have RemainingTurns form part of the key) to do this besides copying, modifying, erasing then inserting what I need to change?
EDIT:
#ildjarn - sorry, I didn't think that mattered. It just returns an int stored within StatusEffect. That int is guaranteed not to change over the runtime of the program.
int StatusEffect::GetPriority() const
{
return StatusPriority;
}
Changing data that affects the ordering of an object will indeed break the invariants of associative containers, but because ActiveStatusEffect::ReminaingTurns is not involved in the ordering of ActiveStatusEffect objects whatsoever, keeping it mutable and modifying its value is perfectly harmless.
I'm concerned because it seems possible for this to mess up the ordering within the set, meaning I can't guarantee the set will always be sorted by effect->GetPrority()
It's a std::set<StatusEffects::ActiveStatusEffect, ASECmp>; how could it sort by any criteria other than that defined by ASECmp?
If you change the key of something in a std::set you are off in Undefined Behaviour land - simple as that. Not only will it "mess up the ordering", but the set will probably stop working correctly altogether.
If the key is unrelated to the actual object, or only a part of it, then you should consider using a map rather than a set:
std::map< int, ActiveStatusEffect > m;
ActiveStatusEffect x = create();
m[ x.effect->GetPriority ] = x; // !!!
Other issues with your code is that you should use some encapsulation (user code should not get access to the internals of the class (i.e. members should not be public).
string var;
void setvar(string ivar)
{
var=ivar;
}
string getVar() const
{
return var;
}
as same way how can i write setter and getter method for a map like this
std::map varmap;
You can write a getter or setter for a field that's a std::map just as you would any other field - just have the getter return a std::map and have the setter accept a std::map.
Of course, if you have a field that's a std::map that you're trying to use getters and setters on, that might suggest that there's a better way to structure the program. Can you provide more details about what you're trying to do?
EDIT: The above answer is for a slightly different question than the one you asked. It seems like what you're interested in is
Given a class with a std::map as a data member, write a function to set a given key/value pair and a function to return the value associated with a given key.
The setter logic for this is not too hard - you just write a function that takes in the key and value and associates the key with the value. For example:
void put(const string& key, const string& value) {
varmap[key] = value;
}
Writing a getter is trickier because there's no guarantee that there's a value associated with a particular key. When this happens, you have multiple options.
You could return a sentinel value. For example, you might return an empty string if the given value isn't stored in the map anywhere. This makes the code for using the function easier to read, but risks using an invalid value in code.
You could throw an exception. This would be good if it represents a serious error for the given value not to exist. This has the drawback that if you look up a value, you always need to try/catch the logic to avoid propagation of errors.
You could associate a default value with the key, then hand that back. If you're writing a program that represents a music library, for example, you might hand back "(none)" or "(unknown)" if you tried to look up the artist for a song on which you have no data, for example.
No one of these approaches works best, and you'll need to think over which is most appropriate to your particular circumstance.
Entries in a std::map<Key, Value> must have a key and a value. The normal way of getting and setting them is:
my_map[a_key] = new_value; // set
do_something_with(my_map[a_key]); // get and use...
If you want to add new functions, they probably wouldn't look like what you're proposing because:
your set is only given one parameter despite needing a key and value (admittedly, you could adopt some convention like having the first ':' or '=' separate them), and
the get() function doesn't provide any key.
You could instead have something more like:
void set(const Key&, const Value&);
std::string get(const Key&) const;
But, even if you have write permissions to do so, you shouldn't add that directly in the map header file - all C++ programs compiled on that computer will share that file and won't expect it to be modified. Any small mistake could cause trouble, and if you ship your program to another computer you won't be able to compile it there without making a similar modification - if that computer uses a different C++ compiler the necessary details of that modification may be slightly different too.
So, you can either write your own (preferably templated) class that derives from (inherits) or contains (composition) a std::map, providing your functions in your custom class. An inheritance based solution is easier and more concise to write:
template <typename Key, typename Value>
struct My_Map : std::map<Key, Value>
{
My_Map(...); // have to provide any non-default constructors you want...
void set(const Key& key, const Value& value) { operator[](key) = value; }
// if you want entries for non-existent keys to be created with a default Value...
Value& get(const Key& key) { return operator[](key); }
--- OR ---
// if you want an exception thrown for non-existent keys...
Value& get(const Key& key) { return at(key); }
const Value& get(const Key& key) const { return at(key); }
};
This is slightly dangerous if you're planning to pass My_Maps around by pointer and accidentally end up with a "new My_Map" pointer that's later deleted as a std::map pointer, as in:
void f(std::map<int, string>* p) { /* use *p */ delete p; }
My_Map<int, string>* p = new My_Map<int, string>;
f(p);
Still, in most programs there's no real danger of accidentally disposing of a map like this, so go ahead and do it.
Further, and this is the kind of thinking that'll make me unpopular with the Standard-fearing purists around here - because My_Map hasn't added any data members or other bases, the std::map<> destructor probably does all the necessary tear-down even though it's technically Undefined Behaviour. I'm NOT encouraging you to ignore the issue (and would consider it unprofessional in a job requiring robustness), but you can at least rest a little easier. I'd be curious to hear from anyone with any compiler/settings where it demonstrably doesn't operate safely.
If you use composition, you'll have to write your own "forwarding" functions to let you use My_Map like a std::map, accessing iterators, find, erase, insert etc.. It's a pain.
Setter and getter for std::map is no different except that you need to pass the necessary parameters for the setter. Assume if I have a struct and has a member variable whose type is std::map, whose key is of type char and data is of type int. Method signatures would be of the format -
void setEncode( char* key, int* data, const int& size ); Because, std::map requires a key, data and sizes of these arrays being passed. With out knowing size, it is unknown as how far to insert the elements in to the container.
std::map<char, int> getEncode() const ; const key word signifies it a non-modifying member function. Because it's functionality is to just return a variable of type std::map.
Example -
struct myMap
{
std::map<char, int> encode;
void setEncode( char* key, int* data, const int& size );
std::map<char, int> getEncode() const ;
};
void myMap::setEncode( char *key, int* data, const int& size )
{
int i=0;
while( i < size )
{
encode.insert(std::pair<char, int>(key[i], data[i]));
++i ;
}
}
std::map<char, int> myMap::getEncode() const
{
return encode;
}
Results IdeOne. This should give you an idea, but should also follow the general rules what #templatetypedef, #tony suggested.
Do you want to set a key value pair in an existing map(probably that's what you want) or create a new map itself?
void setvar(string key, int value)
{
myMap[key] = value;
}
int getVar(string key) const
{
return myMap[key];
}
where int and string are interchangeable
For latter you'll probably have to interate over all map values for setting and getter should be just to return that map pointer.