I wanted to access one "item" of my map<wstring,wstring>.
But this does not work:
for (unsigned int i=0;i<m_ValidCharacterTranslations.Content().size();i++)
{
wstring wsFirst = &m_ValidCharacterTranslations.Content()[i]->first;
wstring wsSecond = &m_ValidCharacterTranslations.Content().at(i)->second;
//do something with these 2 wstrings
}
The error I am getting in the last line is:
No binary operator accepts the right-handed operand of type 'unsigned int'.
My class is declared like this:
clsTranslations m_ValidCharacterTranslations;
class clsTranslations : public CBaseStructure
{
private:
map<wstring,wstring> m_content;
protected:
virtual void ProcessTxtLine(string line);
public:
map<wstring,wstring> &Content();
void LoadTranslations(string file);
};
Can somebody tell me how to get these values?
I would like to iterate through the map and use the first and the
second wstring of the map.
C++11:
for (auto& kvpair : somemap) {
cout << kvpair.first << " has value " << kvpair.second << std::endl;
}
pre C++11:
for (map<wstring,wstring>::iterator it = somemap.begin(); it != somemap.end(); it++) {
cout << it->first << " has value " << it->second << std::endl;
}
You access first and second addresses, instead of values.
Related
I've done some exercises before where I loop through maps no problem. Now that I'm doing so in a class, I'm getting strange errors that I don't understand at all. It seems to happen at the instantiation of the iterator in the print() method.
error: conversion from ‘std::mapstd::__cxx11::basic_string<char,
bool>::const_iterator’ {aka
‘std::_Rb_tree_const_iterator<std::pair<const
std::__cxx11::basic_string, bool> >’} to non-scalar type
‘std::mapstd::__cxx11::basic_string<char, bool>::iterator’ {aka
‘std::_Rb_tree_iterator<std::pair<const
std::__cxx11::basic_string, bool> >’} requested 33 | for
(map<string, bool>::iterator i = jobs.begin(); i != jobs.end(); i++) {
Here is my code:
class Employee {
private:
string name;
map<string, bool> jobs;
public:
Employee() {
name = "";
jobs[""] = false;
}
Employee(const Employee &other) {
cout << "Copied." << endl;
name = other.name;
jobs = other.jobs;
}
Employee(string name, string task, bool trained) {
this->name = name;
jobs[task] = trained;
}
void setTask(string task, bool trained) {
jobs[task] = trained;
}
void print() const {
for (map<string, bool>::iterator i = jobs.begin(); i != jobs.end(); i++) {
pair<string, bool> jobs = *i;
cout << name << " is trained on " << jobs.first << "? " << jobs.second << endl;
}
}
};
I promise I did my best to look for solutions online before coming here. Sorry if I'm misunderstanding something extremely elementary.
I've tried making the print method const or not const, and I've experimented with using const_iterator and .cbegin()/.cend() in case it was being picky about that. Sadly, I'm just not very good at debugging yet.
void print() const
That const in the end means that this class method is a const class method. It can be called on const instances of this class. What it means is that, as far as this method is concerned, all members of its class are const.
map<string, bool>::iterator i = jobs.begin();
Since this is const, the begin() overload returns a const_iterator, instead of iterator, and that's the reason for your compilation error.
I've tried making the print method const or not const,
But what you haven't tried to do is use the current C++ standard, you are apparently using a very, very outdated textbook to learn C++. Current C++ makes all of this much easier:
void print() const {
for (auto &job:jobs)
cout << name << " is trained on " << job.first << "? " << job.second << endl;
}
And that's not even the best way to do it. I'll leave it to you to get your textbook updated, and learn about structured bindings that makes this even cleaner to read.
Your print member function is declared as const, so all occurrences/uses of data members of the class made within it will also be treated as const.
Thus, the calls to jobs.begin() and jobs.end() will invoke the const overloads of those functions, which have return types of const_iterator. So, to fix your issue, make i a const_iterator:
void print() const {
for (map<string, bool>::const_iterator i = jobs.begin(); i != jobs.end(); i++) {
pair<string, bool> localjob = *i; // Avoid "shadowing" member variable!
cout << name << " is trained on " << localjob.first << "? " << localjob.second << endl;
}
}
The member function print is a constant member function. It means that within the function data members of the class are constants. So instead of map<string, bool>::iterator you need to use map<string, bool>::const_iterator
Also it is a bad idea to redeclare the name jobs within the for loop. And moreover this declaration is redundant.
You should write
void print() const {
for (map<string, bool>::const_iterator i = jobs.cbegin(); i != jobs.cend(); i++) {
cout << name << " is trained on " << i->first << "? " << i->second << endl;
}
}
If your compiler supports C++ 17 then you could use range-based for loop the following way
void print() const {
for ( const auto &[first, second] : jobs ) {
cout << name << " is trained on " << first << "? " << second << endl;
}
}
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 am trying to print a map in an organized way. My map is defined like this:
map<std::string,std::vector<message *> > data;
where message is a struct like this:
struct message{
static unsigned int last_id;
unsigned int id;
std::string msg;
std::string timestamp;
message(const std::string& recvbuf_msg,const std::string& a_timestamp) :
msg(recvbuf_msg), timestamp(a_timestamp), id(++last_id)
{
}
};
I tried this way of printing it:
std::cout << (data[username]).at(0)->msg << std::endl;
But it gives a debug error when reaching that function, how can i solve it?
Error R6010 - abort() has been called suggests that either there is no entry for key username in the map, or the vector of messages for that user is empty. You need to make sure the containers are nonempty before accessing elements. It is a good idea to use iterators, here is an example of how to print the messages for all usernames:
for(auto mapIt = data.cbegin(); mapIt != data.cend(); ++mapIt)
{
std::cout << "printing data for " << mapIt->first << ":" << std::endl;
for(auto vectIter = mapIt->second.cbegin(); vectIter != mapIt->second.cend(); ++vectIter)
{
std::cout << (*vectIter)->msg << ", " << (*vectIter)->timestamp << ", "
<< (*vectIter)->id << std::endl;
}
}
The code uses auto, so if you are not using a C++11 compliant compiler, you will have to write the iterator types yourself.
I have a problem in using the std::map correctly. The class Example is a class with an ID, a label, a vector of keypoints and a descriptor matrix. The class Examples is a map for retrieving an example given its ID. The examples are read from files on disk, stored in the map, then used later.
Even if it is conceptually very simple, I am not able to fill the map properly.
I have the following class:
class Example
{
public:
std::string id;
std::string label;
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
Example(std::string id_, std::string label_)
: id(id_), label(label_)
{
// ... nothing ...
}
string to_string() const
{
stringstream ss;
ss << "#" << id
<< " (" << label << ")"
<< " - #keypoints " << keypoints.size()
<< ", descr " << descriptors.rows << " x " << descriptors.cols;
return ss.str();
} // to_string
}; // class Example
ostream& operator <<(ostream & out, const Example &ex)
{
out << ex.to_string();
return out;
} // operator <<
And this one:
// OLD: class Examples : public std::map<std::string, Example*> {
class Examples {
// New line after Martini's comment
std::map<std::string, Example*> _map;
[...]
void fill() {
// create an example
Example *example = new Example(id, label);
// inputstream in
// Read all the keypoints
cv::KeyPoint p;
for(int i=0; ... ) {
in.read(reinterpret_cast<char *>(&p), sizeof(cv::KeyPoint));
example->keypoints.push_back(p); // push_back copies p
} // for
// ... misc code
cv::Mat descr(n_keypoints, d_size, cv_type, cv::Scalar(1));
// ... read Mat from inputstream in, then assign it to the example
example->descriptors = descr;
// SEE THE OUTPUT BELOW
std::cout << "INSERT THIS: " << (*example) << std::endl;
_map.insert(std::pair<string,Example*>(id, example));
std::cout << "READ THIS: " << *(get_example(id)) << std::endl;
// ... other code
} // fill
// Code modified after Martini's comment.
Example* get_example(const std::string &id) const {
std::map<std::string, Example*>::const_iterator it = _map.find(id);
if( it == _map.end()) {
// ... manage error
// ... then exit
} // if
return it->second;
} // get_example
} // class Examples
The output from the insert/get lines is:
INSERT THIS: #122225084 (label) - #keypoints 711, descr 711 x 128
READ THIS: #122225084 (label) - #keypoints 0, descr 0 x 0
In the insert I had a pointer to an example with 711 keypoints and a 711x128 descriptor matrix. If I read the example using its ID right after the insert, I get a pointer to an example with 0 keypoints and an empty matrix.
What am I doing wrong?
Looking into your code one possible explanation is that you already have element in the map with the same key. To diagnose that first of all print value of pointer before you add object and after that (something like this):
std::cout << "INSERT THIS: " << (void *)example << " " << (*example) << std::endl;
_map.insert(std::pair<string,Example*>(id, example));
std::cout << "READ THIS: " << (void *)get_example(id) << " " << *(get_example(id)) << std::endl;
Next or another way is to check result of insert:
if( !_map.insert(std::pair<string,Example*>(id, example)).second )
std::cout << "ERROR: example:" << id << " is already there";
If you want to override element unconditionally you can use oprator[]:
_map[ id ] = example;
If there are really duplicates you will get memory leak (you are getting it anyway) so I would strongly recommend to use smart pointer to store data in your map.
I'm trying to write a copy constructor for an object managing a STL map containing pointers, where the key is a string. However, when I attempt to insert new values in the map, the pointers are set to NULL:
// ...
for(std::map<std::string, data_base*, order>::const_iterator it = other.elements.begin();
it != other.elements.end(); ++it){
data_base *t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
elements[it->first] = t;
std::cout << "INSERTED: " << std::hex << elements[it->first] << std::endl;
}
// ...
other is the object being copied and elements the map. The clone() method returns a pointer to a new object (via new).
Running the code above I get something like:
CLONE: 0xcfbbc0
INSERTED: 0
I'm not a very experienced programmer and this issue is probably simple to fix, but I didnt find any solution to it searching around.
Thanks a lot for your time.
I don't see any problem with this code, other than maybe
std::map<std::string, data_base*, order>::const_iterator it
Here order gives the key comparator to use to sort the pairs contained in the map (often implemented as a tree).
Maybe you're doing something wrong in it, making your [] operator don't find the right ke, making your last line logging a new pair with a null ptr.
First, try without that order, using the default key-comparator (std::less), then if it don't work, post your order definition and the map declaration. If it's not enough, just provide a simple complete program that reproduce the problem.
I just wrote a simple similar test, using the default key-comparator :
#include <map>
#include <string>
#include <iostream>
struct Data
{
int k;
Data* clone() { return new Data(); }
};
typedef std::map< std::string, Data* > DataMap;
DataMap data_map;
int main()
{
data_map[ "hello" ] = new Data();
data_map[ "world" ] = new Data();
DataMap other_map;
for( DataMap::const_iterator it = data_map.begin(); it != data_map.end(); ++it)
{
Data*t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
other_map[it->first] = t;
std::cout << "INSERTED: " << std::hex << other_map[it->first] << std::endl;
}
std::cin.ignore();
return 0;
}
On VS2010SP1, this outputs :
CLONE: 00034DD0
INSERTED: 00034DD0
CLONE: 00035098
INSERTED: 00035098
So it should be the problem, or maybe you're doing something wrong before.
Try this out, to help debug the issue. I'd recommend double-checking that the order function is correct. You can remove it to use std::less<T>, which is known to work.
// ...
typedef std::map<std::string, data_base*, order> string_db_map;
for(string_db_map::const_iterator it = other.elements.begin();
it != other.elements.end();
++it)
{
data_base *t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
std::pair<string_db_map::iterator, bool) result = elements.insert(
string_db_map::value_type( it->first, t));
if ( !result.second )
{
std::cout << "element['" << it->first << "'] was already present, and replaced." << std::endl;
}
std::coud << "INSERTED [iterator]: " << std::hex << (*result.first).second << std::endl;
std::cout << "INSERTED [indexed]: " << std::hex << elements[it->first] << std::endl;
}
// ...