I have a newbie question about how to assign class member (setter). I am used to scripting and mostly there it's done via (in python)
def set_mymember(mymember):
self.mymeber = mymember
My coworker told me "self" and "this" are not needed in C++ , "this" exists and it's not wrong in this context but that would be hard to understand for me so he said I should not care. So I first tried according to his advice:
My class definition: - (it should create a sql query string)
class Query
{
public:
Query() { }
~Query() { }
void setoptions( std::string qtext_where="", bool qtext_erl=true, std::vector<std::string> kids=std::vector<std::string>() );
Query build_query( );
void set_db_table( std::string db_table );
void set_db_key( std::string db_key );
void set_m_qtext( std::string m_qtext );
void set_foo( std::string foo );
std::string sql();
std::string get_sql_update();
private:
std::string m_db_table; // Tabellenname
std::string m_db_key; // Tabellen-key
std::string m_qtext_where; // add.optionale where clause
std::string m_qtext; // fertiger SELECT
std::string m_sql_update; // fertiger UPDATE
bool m_erl; // nur erledigte waehlen?
std::vector<std::string> m_kids; // Liste von keys zu selecten
};
ANd here's one of the setter methods: I call them with filled string and vector, double check it in this code
void Query::setoptions( string qtext_where, bool erl, vector<string> kids ) {
m_qtext_where = qtext_where;
m_erl = erl;
m_kids = kids;
}
But when my app later calls query.build_query()
the variables are empty
Query Query::build_query( ) {
cout << "kids size" << m_kids.size() << endl;
cout << "m_qtext_where " << m_qtext_where << endl;
// Query zur auswahl der zu uebertragenden Datensaetze
string sql_update = "UPDATE " + m_db_table;
string qtext = "SELECT * FROM " + m_db_table;
string qtext_order = " ORDER BY " + m_db_key;
(...)
EDIT: So here's part of the app code which calls 1.setoptions, and 2.build_query
// read file line by line into vector of strings
vector<string> text_file;
ifstream ifs( input );
string temp;
while( getline( ifs, temp ) ) {
if (temp.substr(0,1) == "#" ) {
cout << "COMMENT: " << temp << endl;
continue;
}
cout << temp << endl;
text_file.push_back( temp );
}
// check: yes, vector has a size = number of lines
cout << "text_file size " << text_file.size() << endl;
// create Query object
Query query = Query();
// set the members, bool erl = true
query.setoptions( "", erl, text_file );
// call 2nd method
q2 = query.build_query();
Can't really tell whats going on without the full code, but I suspect that you're returning a query object from query.build_query that isn't a full copy of the query object, if that makes sense? Can you include the full text of build_query?
Also, I'd make the build_query method void, and not try to assign a fresh Query object back to a second Query object (q2) at all (unless you really need to, again, can't really tell without the full code), something like this:
void Query::build_query( ) {
std::cout << "kids size" << m_kids.size() << std::endl;
std::cout << "m_qtext_where " << m_qtext_where << std::endl;
}
main
{
...
Query query = Query();
// set the members, bool erl = true
query.setoptions( "", true, text_file );
// call 2nd method
query.build_query();
}
Also, just being pedantic here, but given that you're providing default args for all the options, I'd be inclined to initialise them in the constructor like this:
Query::Query()
: m_qtext_where("")
, qtext_erl(true)
, kids (std::vector<std::string>()
{}
And then instead of a setOptions method, have setters for each individual variable:
void setWhere(std::string qtext_where) {m_qtext_where = qtext_where ;}
void setErl(bool query_erl) { m_erl = query_erl; }
void setKids(std::vector<std::string> kids) { m_kids = kids; }
which you call only when you need to..
Related
I have wrote an API as defined below. This API is used to find the index of a filename in a file system. The filesystem is coming from an Android device through mtp. What I'm doing is to request a list of files stored on the Android device and compare each file listed to the one I'm looking for 'name2look'
I have created a vector table to store what I'm doing but it's not mandatory. My concerns is that the variable name2look contain the right name I'm looking for "Pictures"
uint32_t USBDevice::GetIndexFromName(LIBMTP_mtpdevice_t *dev, uint32_t storage,const char *name2look)
{
uint32_t idx_fold = 1;
std::vector<MyFileTreeItem*> FSimage;
LIBMTP_file_t *files;
LIBMTP_file_t *file;
std::cout << "NAME : " << name2look << "\n";
files = this->GetFileAndFolder(dev, storage,0);
file = files;
while (file != NULL) {
MyFileTreeItem* FSitem = new MyFileTreeItem();
FSitem->filename = file->filename;
FSitem->index = file->item_id;
FSitem->FileType = file->filetype;
FSimage.push_back(FSitem);
std::cout << "NAME : " << name2look << "\n";
std::cout << "FS NAME : " << file->filename << "\n";
if(std::strcmp(file->filename, name2look)==0) {
std::cout << "FIND IDX : " << file->item_id << "\n";
return file->item_id;
}
file = file->next;
}
return 0;
}
The Log is showing that the first display 'std::cout' is ok. the variable name is still 'Pictures' but when I ask to display it after in the "while" the variable name2look change and is not the same anymore.
First display
NAME : Pictures
second one in the while
NAME : Martin).mp3
FS NAME : Music
How is it possible to be corrupted ??
The function is called by a Qt C++ code:
void MyButtonGroup::buttonClick(QAbstractButton *button)
{
uint32_t status;
QList<QTreeWidgetItem *> itemList;
uint32_t index = 0;
if (button->text() == "Create Folder") {
itemList = this->MyTree->selectedItems();
QString str = itemList[0]->text(0);
char *utf8_text = str.toLatin1().data();
if(utf8_text != NULL)
{
std::cout << "A CHERCHER " << utf8_text << "\n";
index = this->MyDevice.GetIndexFromName(this->dev_id, storage->id, utf8_text);
}
else
index = 0;
CreateFolderDialog *dialog = new CreateFolderDialog(this->MyTree, this->MyDevice, this->dev_id, this->storage, index);
dialog->show();
}
utf8_text report the right value.
Any idea ?
This might be the problem. I am not sure. Check it out.
This line:
char *utf8_text = str.toLatin1().data();
What does the documentation say toLatin1() does? It creates a new QByteArray object and then you call data() on that and you get a pointer to character and then the QByteArray is destroyed at the end of the line because it was TEMPORARY.
And now you have an invalid pointer to freed memory that you then pass into your function. It probably gets overwritten by the first call to new() in your function.
I think you should change it to something like this:
QByteArray latin_str = str.toLatin1();
char *utf8_text = latin_str.data();
Your name utf8_text is weird since you just converted it to Latin1 which isn't UTF8.
I just came from Java and Python world to C++ world, and faced a problem while trying to get the value from a public const function of a class.
I have a class as follows:
class CMDPoint
{
public:
CMDPoint();
CMDPoint(int nDimensions);
virtual ~CMDPoint();
private:
int m_nDimensions; // the number of dimensions of a point
float* m_coordinate; // the coordinate of a point
public:
const int GetNDimensions() const { return m_nDimensions; }
const float GetCoordinate(int nth) const { return m_coordinate[nth]; }
void SetCoordinate(int nth, float value) { m_coordinate[nth] = value; }
};
Ultimately, I wish to write all the clusterPoints in clusterPointArray into the file. However, now I am just testing it with the first clusterPoint (thus, GetCoordinate(0)).
ofstream outFile;
outFile.open("C:\\data\\test.txt", std::ofstream::out | std::ofstream::app);
for (std::vector<CMDPoint> ::iterator it = clusterEntry->clusterPointArray.begin(); it != clusterEntry->clusterPointArray.end(); ++it)
{
outFile << ("%f", (*it).GetCoordinate(0)); // fails
outFile << " ";
}
outFile << "\n";
outFile.close();
The problem is I only see the " " in the file. No coordinate has been written in. Did I do anything wrong while fetching the value from const float GetCoordinate(int nth)?
try to change this
outFile << ("%f", (*it).GetCoordinate(0)); // fails
to this:
outFile << (*it).GetCoordinate(0); // OK
Because the ("%f", (*it).GetCoordinate(0)) represents nothing , only a enumerations of expressions separated by , . It will not be evaluated into a pair of objects as in java is i think.
Edit:("%f", (*it).GetCoordinate(0)) actually evaluates to the last element that is (*it).GetCoordinate(0) ( PlasmaHH comment ) so it should still print something. However if nothing is printed then the collection clusterEntry->clusterPointArray could be empty and the code inside the for loop might not be executed ever.
Hope this helps,
Razvan.
outFile << it->GetCoordinate(0);
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.
Newbie programmer here trying to work out his homework. I'm trying to use a STL set of classes, but the compiler complains about my code.
car.h
#include <string>
#include <iostream>
#include <time.h>
#include <set>
class Car
{
private:
std::string plateNumber;
std::string description;
std::string dateIn;
std::string timeIn;
public:
Car() {};
~Car() {};
Car(std::string plate, std::string desc)
{
plateNumber = plate;
description = desc;
};
void setPlateNumber(std::string plate) ;
std::string getPlateNumber() const;
void setDesc(std::string desc);
void setTimeDateIn() ;
std::string getTimeIn() const;
std::string getDateIn() const;
std::string getDesc() const;
friend std::ostream & operator<<(std::ostream & os, Car &c);
};
std::ostream & operator<<(std::ostream & os, Car& c)
{
os << "Plate Number: " << c.plateNumber << ", Date In: " << c.dateIn << ", " <<
`"Time in: " << c.timeIn << "Description: " << c.description << std::endl;
return os;
}
bool operator< ( const Car& lhs, const Car& rhs)
{
return ( lhs.getPlateNumber() < rhs.getPlateNumber() );
};
main.cpp
#include "stdafx.h"
#include <iostream>
#include <set>
#include <string>
#include "car.h"
void carEnters(std::set<Car> g);
void carLeaves(std::set<Car> g);
void displayContents(std::set<Car> g);
int main ()
{
char choice [80];
// initialize the sets and iterators
std::set<Car> garage;
do // Loop until user quits
{
std::cout <<
std::endl;
std::cout << "Menu:" << std::endl;
std::cout << "-----" << std::endl;
std::cout << "'1' to enter a new car, or " << std::endl;
std::cout << "'2' to exit the front car, or " << std::endl;
std::cout << "'3' to to list all the cars or." << std::endl;
std::cout << "'0' to close the garage: " << std::endl;
std::cin.getline( choice, 1, '\n');
switch ( choice[0] )
{
case '0' :
std::cout << std::endl << "Thanks for playing...\n";
break;
case '1' :
carEnters(garage);
break;
case '2' :
carLeaves(garage);
case '3' :
displayContents(garage);
break;
default:
std::cout << "I'm sorry, I didn't understand that.\n";
break;
}
} while ( choice[0] != '0' ); // Loop again if the user hasn't quit.
return 0;
}
void carEnters( std::set<Car> g)
{
// Car enters garage
std::cout << "Please enter the plate number:" << std::endl;
std::string plate;
std::cin >> plate;
std::cin.ignore();
std::set<Car>::iterator findPlate;
Car* lookup = new Car;
lookup->setPlateNumber(plate);
findPlate = g.find(*lookup);
if (findPlate != g.end()) // Add car to garage
{
Car *currentCar = new Car ;
// Set car parameters
std::cout << "Please type the entering car's description <Model, Color...
> : " << std::endl;
char desc[80];
std::cin.get(desc, 80 );
std::cin.ignore();
currentCar->setDesc(desc);
currentCar->setTimeDateIn();
currentCar->setPlateNumber(plate);
g.insert(currentCar);
}
else // Plate is already in garage set
{
std::cout << "Sorry, this car is already in the garage!" <<
std::endl;
}
}
void carLeaves( std::set<Car> g)
{
std::string plate;
std::cout << "Which plate is leaving?" << std::endl;
std::cin >> plate;
std::cin.ignore();
// Find car's plate number in the garage set
// for (findPlate=garageSet.begin(); findPlate !=garageSet.end(); findPlate++)
std::set<Car>::iterator findPlate;
Car lookup(plate,"");
findPlate = g.find(lookup);
if (findPlate != g.end())
{
// Display time in and then remove car from set of cars
std::cout << "Car out at " << (*findPlate).getDateIn() << ", " <<
(*findPlate).getTimeIn() << std::endl;
g.erase(findPlate);
}
else
{
std::cout << "Car was not found in set of Cars!" << std::endl;
}
}
// Car class function implementation
void Car::setPlateNumber(std::string p)
{
plateNumber = p;
}
std::string Car::getPlateNumber() const
{
return plateNumber;
}
void Car::setDesc(std::string d)
{
description = d;
}
void Car::setTimeDateIn()
{
char dat[9];
char tim[9];
_strdate_s(dat);
_strtime_s(tim);
dateIn=dat;
timeIn=tim;
}
std::string Car::getTimeIn() const
{
return timeIn;
}
std::string Car::getDateIn() const
{
return dateIn;
}
std::string Car::getDesc() const
{
return description;
}
// Display the car set
void displayContents(std::set <Car> garage)
{
// function displays current contents of the parking garage.
std::set <Car>::iterator carIndex;
std::cout << std::endl << "Here are all the cars parked: " << std::endl;
for (carIndex = garage.begin();
carIndex != garage.end();
++carIndex )
{
std::cout << " " << carIndex->getPlateNumber() << ", Date In: " <<
carIndex->getDateIn() << ", " << "Time In: " << carIndex->getTimeIn() << "Description:
" << carIndex->getDesc() << std::endl;
}
}
The error I get from the compiler is this:
xmemory(208): error C2664: 'Car::Car(const Car &)' : cannot convert parameter 1 from 'Car *' to 'const Car &'
Reason: cannot convert from 'Car *' to 'const Car'
No constructor could take the source type, or constructor overload resolution was ambiguous
I'm not sure where I'm going wrong, would some please point out how my overload is incorrect?
Thanks
The error is likely the g.insert(currentCar) line in the carEnters method, as g is a std::set<Car>, not a std::set<Car*>. Either pass in a reference to the current car (*currentCar) or make the garage contain pointers to cars.
In addition, you may wish to pass in g as a reference, in the form of...
void carEnters(std::set<Car>& g) { }
void carLeaves(std::set<Car>& g) { }
Otherwise the set is being copied and you might not get the results you want.
If you need explanation as to the why for any of these, add a comment. I used to do some TAing back in the day. :)
I believe #James is on the right track, but passing *CurrentCar isn't really the right answer (at least IMO). Instead, you should back up a bit:
Car *currentCar = new Car ;
Perhaps you have prior experience with Java (or something similar) where this is a routine, normal type of code to write. In C++, however, using new directly is (or at least should be) fairly unusual. What you almost certainly want instead is:
Car currentCar;
and then you'll fill in the fields like:
currentCar.whatever = x;
Then, when you put your currentCar into the std::set (or whatever) you won't have to dereference anything, because you'll be starting with a Car object, which is what's expected. As an aside, I'd note that when you look up the car, you're also creating a Car object dynamically -- but you never seem to delete either one, so you're code is leaking memory.
Edit: I should add that there are alternatives that may be preferable. Right now, you're basically treating a Car as "dumb data", with outside code to operate on that data. If you want your code to be "object oriented", it would almost certainly be better to move the code for reading a Car's data into the class itself, so outside code would just invoke that member function.
Another possibility would be to make a Car an immutable object. Instead of creating an unitialized car, and then setting the appropriate values in that object, I'd pass the correct values to Car's constructor, and eliminate the member functions you currently have for changing those values. At least for your purposes, it doesn't appear that you need to actually change a car's plate number -- it should apparently only ever have one plate number, in which case it would be better for your code to reflect (and enforce) that directly.
Your problem is that your set takes elements of type Car but you are inserting elements of type Car*:
void carEnters( std::set<Car> g)
{
...
Car *currentCar = new Car;
...
g.insert(currentCar);
In this case, currentCar is a pointer to a Car and g.insert expects a Car. There are multiple ways of fixing this - you can change your set to use Car* although your overloaded operator< will no longer work (you'll have to create a functor that is passed to the set and takes two Car*s). You can change currentCar to be of type Car. This results in a bunch of copying however. Or you can ditch currentCar entirely and make a constructor that will set all the variables you need set:
Car(const std::string &plate, const std::string &desc)
{
plateNumber = plate;
description = desc;
setTimeDateIn();
};
then you can just do this:
g.insert(Car(desc, plate));
Which is actually preferable to what you are doing now, as someone might forget to call setTimeDateIn. It makes more sense for that to be called when the Car is constructed.
I have the following functor:
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
It is supposed to be a strict weak ordering, and it's this long (could be one line only) for debug purposes.
I'm using this functor as a comparator functor for a stl::set. Problem being, it only inserts the first element. By adding console output to the comparator function, I learned that it's actually comparing the file name to itself every time.
Other relevant lines are:
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
and
// (FileSet files_;) <- SimulatedDisk private class member
void SimulatedDisk::addFile(SimulatedDiskFile * file) {
files_.insert(file);
positions_calculated_ = false;
}
EDIT: the code that calls .addFile() is:
current_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
current_request++;
}
Where all_requests is a list, and class Request is such that:
class Request {
private:
string file_name_;
int response_code_;
int response_size_;
public:
void setFileName(string file_name);
string getFileName();
void setResponseCode(int response_code);
int getResponseCode();
void setResponseSize(int response_size);
int getResponseSize();
};
I wish I could offer my hypotesis as to what's going on, but I actually have no idea. Thanks in advance for any pointers.
There's nothing wrong with the code you've posted, functionally speaking. Here's a complete test program - I've only filled in the blanks, not changing your code at all.
#include <iostream>
#include <string>
#include <set>
using namespace std;
class SimulatedDiskFile
{
public:
string getFileName() { return name; }
SimulatedDiskFile(const string &n)
: name(n) { }
string name;
};
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
int main()
{
FileSet files;
files.insert(new SimulatedDiskFile("a"));
files.insert(new SimulatedDiskFile("z"));
files.insert(new SimulatedDiskFile("m"));
FileSet::iterator f;
for (f = files.begin(); f != files.end(); f++)
cout << (*f)->name << std::endl;
return 0;
}
I get this output:
z and a: false
a and z: true
z and a: false
m and a: false
m and z: true
z and m: false
a and m: true
m and a: false
a
m
z
Note that the set ends up with all three things stored in it, and your comparison logging shows sensible behaviour.
Edit:
Your bug is in these line:
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
You're taking the address of a local object. Each time around the loop that object is destroyed and the next object is allocated into exactly the same space. So only the final object still exists at the end of the loop and you've added multiple pointers to that same object. Outside the loop, all bets are off because now none of the objects exist.
Either allocate each SimulatedDiskFile with new (like in my test, but then you'll have to figure out when to delete them), or else don't use pointers at all (far easier if it fits the constraints of your problem).
And here is the problem:
SimulatedDiskFile temp_file(current_request->getFileName(),
current_request->getResponseSize());
disk.addFile(&temp_file);
You are adding a pointer to a variable which is immediately destroyed. You need to dynamically create your SDF objects.
urrent_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(...blah..blah..); ====> pointer to local variable is inserted
disk.addFile(&temp_file);
current_request++;
}
temp_file would go out of scope the moment next iteration in while loop. You need to change the insert code. Create SimulatedDiskFile objects on heap and push otherwise if the objects are smaller then store by value in set.
Agree with #Earwicker. All looks good. Have you had a look inside all_requests? Maybe all the filenames are the same in there and everything else is working fine? (just thinking out loud here)