//Inside the header.h
class telefonbok{
std::map<std::string,std::string> telebok;
std::map<std::string,std::string> aliasbok;
}
//Inside the cpp file
void telefonbok::alias(string name, string alias){
if (telebok.find(name) == telebok.end()) {
cout << "Not found" << endl;
} else {
//pointer = Adress stored in pointer.
//*pointer = Value of *pointer
string *pointer;
pointer = &telebok.find(name)->second;
aliasbok.insert(make_pair(alias, *pointer));
cout << *pointer << endl;
}
When i change the value in the first map(telebok) the second value in the map(aliasbok) stays the same (the one who is supposed to have the pointer as the value).
Example:
add peter 123
lookup peter:
peter : 123
alias peter pete
lookup pete:
pete : 123
change peter 987
lookup peter:
peter : 987
lookup pete:
pete : 123
(Pete never changes wich is the issue, it's supposed to always have the same value as peter)
First of all your code is inefficient (you call find twice, which is pretty expensive operation), so you should work with iterators, not pointers and it also will help to resolve your issue:
class telefonbok{
typedef std::map<std::string,std::string> Telebok;
typedef std::map<std::string,Telebok::const_iterator> Aliasbok;
Telebok telebok;
Aliasbok aliasbok;
};
void telefonbok::alias(string name, string alias)
{
Telebok::const_iterator f = telebok.find( name );
if( f == telebok.end() )
cout << "Not found" << endl;
else
aliasbok.insert( make_pair( alias, f );
}
now you have following:
you do not call std::map::find() twice
through alias you can not only find number but original name as well
to print values from alias code little bit more complicated:
for( Aliasbok::const_iterator it = aliasbok.begin(); it != aliasbok.end(); ++it )
cout << "alias " << it->first << " has number " << it->second->second << " original name " << it->second->first << endl;
or to find a value:
Aliasbok::const_iterator it = aliasbok.find( "abcd" );
if( it != aliasbok.end() )
cout << "phone for " << it->first << " is " << it->second->second << endl;
else
cout << "phone for abcd not found" << endl;
but you should get used to it when using iterators
Note: if you delete records from phonebook you need to clean aliasbook first, otherwise it will hold invalid iterators. Proper solution would be to use boost::multi_index but that probably too complicated for your level.
When i change the value in the first map(telebok) the second value in the map(aliasbok) stays the same (the one who is supposed to have the pointer as the value).
If the aliasbok is supposed to have pointer as the value, then your bug is that you've defined the map incorrectly. Here is your definition:
std::map<std::string,std::string> aliasbok;
Pay attention to how the value type of the map is std::string which is a value type and not std::string* which would be a pointer type.
Also pay attention to this line:
aliasbok.insert(make_pair(alias, *pointer));
Where you dereference the pointer and copy the pointed string into the pair, instead of copying a pointer.
You have to store shared pointers and set them apropriatelly to the same string.
class telefonbok{
std::map<std::string,std::shared_ptr<std::string>> telebok;
std::map<std::string,std::shared_ptr<std::string>> aliasbok;
}
and provide the methods to update the pointers as needed e.g.
void addphone(std::string const & name,
std::string const & alias,
std::string const & phone);
{
std::shared_ptr<std::string> phone_ptr(new std::string(phone));
telefonbok.telebok.emplace(name,phone_ptr);
telefonbok.aliasbok.emplace(alias,phone_ptr);
}
and this way when you modify the phone on either it will get updated on both. Your phone will also not die when you exit the scope of the function.
Then you can do this for updates
void update_phone(std::string const & name,
std::string const & newphone)
{
if( auto iter = telefonbok.telebok.find(name) )
{
*(iter->second.get()) = newphone;
} else if ( auto iter = telefonbok.aliasbok.find(name) )
{
*(iter->second.get()) = newphone;
}
}
Related
I'm new to C++ and I have a vector of doctors.
I add a new doctor with the following code:
void DoctorAdmin::setDoctor(std::string lastname, std::string forename,
Person::Sex sex){
//Create new doctor
Doctor* doc = new Doctor(lastname, forename, sex);
//insert at the end of the vector
doctors.push_back(doc);
}
Then I want to show their information on the console:
void DoctorAdmin::showDoctors(){
cout << "Doctors:" << endl;
cout << "Name" << "\t\t\t" << "Forename" << "\t\t\t" << "Sex" << endl;
for (vector<Doctor*>::iterator i = doctors.begin(); i != doctors.end(); i++){
Doctors* doc = doctors.at(i);
cout << doc->getName() << "\t\t\t" << doc->getForename() << "\t\t\t"
<< doc->getSex() << endl;
}
After doing it like this I get two Errors:
E0304 No instance of overloaded function "std::vector<_Ty, _Alloc>::at [mit _Ty=Doctors *, _Alloc=std::allocator<Doctors *>]" matches the argument list.
// and
C2664 "Doctors *const &std::vector<Doctors *,std::allocator<_Ty>>::at(const unsigned int) const" : cannot convert from Argument "std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>" in "const unsigned int"
How do I use the vector iterator correctly to avoid this?
An iterator is not index-like, it is pointer-like.
for (vector<Arzt*>::iterator doc = aerzte.begin(); doc != aerzte.end(); doc++)
{
cout << (*doc)->getName() << "\t\t\t" << (*doc)->getVorname() << "\t\t\t"
<< (*doc)->getGeschlecht() << endl;
}
It seems like you are confused as to when you need to new things too. Most of the time you don't need new
vector<Arzt> aerzte;
void ArztAdmin::anlegenArzt(std::string name, std::string vorname, Person::Geschlecht geschlecht){
// Create new doctor at the end of the vector
aerzte.emplace_back(name, vorname, geschlecht);
}
You can also directly bind references as loop variables
for (Arzt & doc : aerzte)
{
cout << doc.getName() << "\t\t\t" << doc.getVorname() << "\t\t\t"
<< doc.getGeschlecht() << endl;
}
The at function requires an index, but a vector<Arzt*>::iterator is not an index, neither semantically nor technically. An iterator points directly to an element, whereas an index represents the distance between a container's start and the element in a container that allows random element access.
Because an iterator points directly to an element, the at function isn't even necessary in your loop. *i yields the element:
Arzt* doc = *i;
Beginning with C++11, the code for such simple loops can be written in a shorter way using auto:
for (auto i = aerzte.begin(); i != aerzte.end(); i++){
The compiler knows what type i really is because it knows what begin() returns.
Even better, use a range-based loop:
for (auto doc : aerzte){
cout << doc->getName() << "\t\t\t" << doc->getVorname() << "\t\t\t"
<< doc->getGeschlecht() << endl;
}
And while we're at it, don't use dynamic memory allocation when you don't have to. This isn't Java or C#; new is dangerous territory in C++ and should be avoided:
#include <vector>
#include <string>
#include <iostream>
struct Arzt
{
Arzt(std::string const& name, std::string const& vorname) :
name(name),
vorname(vorname)
{
}
std::string name;
std::string vorname;
// Geschlecht omitted for brevity's sake
};
int main()
{
std::vector<Arzt> aerzte;
Arzt doc1("foo", "bar");
Arzt doc2("foo", "bar");
Arzt doc3("foo", "bar");
aerzte.push_back(doc1);
aerzte.push_back(doc2);
aerzte.push_back(doc3);
for (auto const& arzt : aerzte)
{
std::cout << arzt.name << ' ' << arzt.vorname << '\n';
}
}
As you are no longer iterating over pointers but over larger objects, const& should be used in the for loop.
I have a map that looks like
map<string , map<int,int>>
the string contains name of a student, the nested map contains ID as key and age as value. When I print the map, it al prints values as it should.
However, I want to find a students with a certain ID and lower. I tried using lower_bound using:
for( auto &x : class ){
auto it = x.second.upper_bound(some_number);
for( ; it != x .second.begin() ; --it){
cout << x.first << " = " << << it -> first << " " <<it -> second << endl;
}
}
This indeed prints right names of students, but their IDs and ages are just zeros or random numbers, what is causing this behavior? It works when I just print it.
I tried to found out about this on cpp map reference but found nothing.
Following code solves your problem:
for( auto &x : Class ){
auto it = x.second.upper_bound(some_number);
while(it!=x.second.begin()){
it=prev(it);
cout<< x.first<< " = "<< it->first<< " "<< it->second<< endl;
}
}
Refer std::map::upper_bound
What above code does is, first it finds the iterator with id strictly greater than some_number. Now because we want to print "students with a certain ID and lower", we print all the id's lower than the return value of upper_bound.
The stopping condition is that if iterator is itself x.second.begin(), that means now we don't have any id's smaller than it.
Plus your data structure is strange, you should have student ID as your primary index.
map<int, pair<string,int> > would be more appropriate data structure. (Assuming unique id's which is mostly the case).
Although, you could do lot better using OOP concepts.
What you see is probably undefined behaviour, std::map::upper_bound returns also end iterator under some conditions and from your code it does not look like you check for this condition. Also you should not use class keyword as variable name for your map, I am preety sure it does not compile. Below is a sample code that should work with no UB and print all IDs less than some number including this ID:
http://coliru.stacked-crooked.com/a/efae1ae4faa3e656
map< string , map<int,int>> classes ={
{ "k1", {{1,1},{2,2},{3,3}} }
};
//int class;
int some_number = 4;
for( auto &x : classes ){
auto it_num_end = x.second.upper_bound(some_number); // some numberis just variable that contains number
for( auto it = x.second.begin(); it != it_num_end ; ++it){
cout << x.first << " = " << it -> first << " " <<it -> second << endl;
}
}
I observe some weird behavior today , the code is as follow :
The Code :
#include <iostream>
struct text
{
char c;
};
int main(void)
{
text experim = {'b'};
char * Cptr = &(experim.c);
std::cout << "The Value \t: " << *Cptr << std::endl ;
std::cout << "The Address \t: " << Cptr << std::endl ; //Print weird stuff
std::cout << "\n\n";
*Cptr = 'z'; //Attempt to change the value
std::cout << "The New Value \t: " << *Cptr <<std::endl ;
std::cout << "The Address \t: " << Cptr << std::endl ; //Weird address again
return 0;
}
The Question :
1.) The only question I have is why cout theAddress for the above code would come out some weird value ?
2.)Why I can still change the value of the member c by dereferenncing the pointer which has weird address ?
Thank you.
Consider fixing the code like this:
std::cout << "The Address \t: " << (void *)Cptr << std::endl ;
There's a std::ostream& operator<< (std::ostream& out, const char* s ); that takes a char* so you have to cast to void* to print an address, not a string it "points" to
I think the "weird" stuff shows up because cout thinks it's a cstring, i.e. a 0-terminated character array, so it doesn't print the address as you expected. And since your "string" isn't 0-terminated, all it can do is walk the memory until it encounters a 0. To sum it up, you're not actually printing the address.
Why I can still change the value of the member c by dereferenncing the
pointer which has weird address
The address isn't weird, as explained above. In your code Cptr points to a valid memory location and you can do pretty much anything you want with it.
I have a problem in my code which i can't understand. I want to make a list of lists and use it like a two-dimensional associative array.
Something like this:
token["window"]["title"] = "Amazing!";
cout << token["window"]["title"]; //Amazing!
The second line works good. Data is readed from file. Problem is with the first instruction.
This is how i overload the second square brakcets:
TokenPair Token::operator[](string keyName){
for( list<TokenPair>::iterator pair=keys.begin(); pair != keys.end();++pair){
if(pair->key == keyName){
return *pair;
}
}
}
As you see I return object of class TokenPair. To properly get the value from object (field TokenPair::value) i overload streaming and casting on string().
TokenPair::operator string() const{
return value;
}
ostream & operator<< (ostream &stream, const TokenPair &pair){
return stream << pair.value;
}
And as i say before getting value works great. Problem is with overloading operator of attribution:
TokenPair TokenPair::operator=( const string newValue ){
value = newValue;
return *this;
}
This method assing the value but it not remember that! For example:
token["window"]["title"] = "Ok";
will cause that inside method TokenPair::operator= variable newValue=="Ok" and after the first line even value is set to "Ok"; But when i later do:
cout << token["window"]["title"] ;
the field in TokenPair is still not changed. I want to ask: Why? Maybe iterators return a copy of that object? I don't know. Please help.
Your problem is that the operator[] returns a TokenPair by value, so when assigning you assign the new value to a temporary, not to the object stored in the list.
For this to work the operator[] should return a reference to the object you want to modify.
Here is an example of how to use a map-of-maps:
#include <map>
#include <string>
#include <iostream>
#include <sstream>
const char inputString[] =
"President 16 Lincoln "
"President 1 Washington "
"State Best Illinois "
"State Biggest Alaska ";
int main () {
std::map<std::string, std::map<std::string, std::string> > token;
std::string primary, secondary, result;
std::istringstream input(inputString);
while( input >> primary >> secondary >> result )
token[primary][secondary] = result;
std::cout << "Abe " << token["President"]["16"] << "\n";
std::cout << "Springfield, " << token["State"]["Best"] << "\n";
std::cout << "Blank: " << token["President"]["43"] << "\n";
}
I have a map storing a "job" as a key and a "name" as the value it stores.
map<string, string>dutyAndJob;
map<string,string>::iterator it;
I'm basically trying to look through this map for a particular "name".
If the name isn't there, it shouldn't enter this loop, however, for some unknown reason, it always enters this loop:
string name = "Bob";
it = dutyAndJob.find(name);
if (it == dutyAndJob.end())
{
cout << "Testing : " << name << endl;
}
For some reason, it would still enter this loop even though there isn't a Bob stored in the map.
Any help would be greatly appreciated!
if (it == dutyAndJob.end())
{
cout << "Testing : " << name << endl;
}
should be:
if (it != dutyAndJob.end()) // Does it refer to a valid association
{
cout << "Testing : " << name << endl;
}
Notice the change from == to != indicating that the key was found in the map. The iterator it is only equal to dutyAndJob.end() if the key was not found.
Just realized that Job is the key, and Name is the data. The way you have it structured, you can only use find on the Job that will retrieve the Name.
string job = "Cashier";
it = dutyAndJob.find(job);
if (it == dutyAndJob.end())
{
cout << "Testing : " << job<< endl;
}
If you actually wanted to search by Name, maybe the Name should be the key, and the Job should be the data?