std::vector<> assignment operation not working; need 'clear' operation first - c++

I am confused by what I thought should be a very simple operation. I call a method that creates a std::vector and returns it. Then I set an existing std::vector to that result, expecting the = operator to work. The code looks like this:
std::vector<BTLECharDecl> charDeclList;
charDeclList.clear();
// get the services on the agent
// It loads the discovered services into the class variable 'serviceList'
if((result = discoverServices()) != rc_SUCCESS)
{
std::cout << "Discovering service failed. Function returned message "
<< eResultCode2str(result) << "(" << hex << result << dec << ")" << endl;
return result;
}
if(serviceList.size() > 0)
{
for(uint16 i = 0; i < serviceList.size(); i++)
{
// Get chararcteristic Declaration List as Objects for each service
startHandle = serviceList.at(i).getServiceData().startHandle;
endHandle = serviceList.at(i).getServiceData().endHandle;
if(startHandle < endHandle)
{
// !! WHY DO I NEED THIS clear()?? !!
charDeclList.clear();
charDeclList = discoverCharDecl(serviceList.at(i).getServiceData().startHandle, endHandle);
}
If I do not invoke the charDeclList.clear() method before the call to the method that returns this type of object, I will get leftover garbage from previous loops. Not always, but sometimes. I would have expected the assignment operator to completely replace whatever was there with that which is returned by the called method. What is wrong with my thinking? (Invoking the clear() solves the problem but it is unsettling.) Working with MS Visual Studio 2008.

Related

Memory error on displaying opencv matrix

I made a class consuming a serialized Opencv matrix. It is working fine and the Matrix is deserialized. If I try to display it inside the method of the class using the imshow method, it will work perfectly well, displaying without error. However, I am passing a parameter reference to a Matrix pointer from my main function in order to further process this matrix. When I try to display it in the main, I end up with a segmentation fault.
The weird part is that if I try to display the matrix in both the class method and the Main, I will end up with two windows working fine (sometimes I will get a segmentation fault but most of the time it works good).
If I remove the displaying code from the method, I won't even be able to display one frame before getting a segmentation fault.
I have tried using a shared_ptr, passing a pointer to the pointer instead of a reference, or even simply returning the value.
My code is kind of messy but the main aim of it is testing.
Here is the code of the method :
void VideoConsumer::getVideoFrame(cv::Mat* &mat) {
Message msg = _consumer->poll();
mat = NULL;
if(!msg) {
cerr << "No message received" << endl;
return;
}
if(msg.get_error()) {
if(!msg.is_eof()) {
cerr << "[+] Received error notification: " << msg.get_error() << endl;
}
return;
}
Document document;
string jsonPayload = "";
for(auto i=msg.get_payload().begin(); i != msg.get_payload().end();i++) {
jsonPayload += *i;
}
document.Parse(jsonPayload.c_str());
if(document.HasMember("rows") && document.HasMember("cols") && document.HasMember("data")) {
int rows = document["rows"].GetInt();
int cols = document["cols"].GetInt();
int type = document["type"].GetInt();
string data = document["data"].GetString();
std::vector<BYTE> decodedBytes = base64_decode(data);
stringstream ss;
for(int i=0;i< decodedBytes.size(); i++) {
ss << decodedBytes[i];
}
string decoded_data = ss.str();
cout << "Constructed string" << endl;
mat = new cv::Mat(rows,cols,type,(void *)decoded_data.data());
/*cv::imshow("test",*mat);
while(cv::waitKey(10) != 27)*/ //This is where it is displayed
return;
} else {
return;
}
}
And the code in the main :
...
if(parser.has("stream")) {
VideoConsumer consumer("localhost:9092","video-stream-topic","testId2");
consumer.setConsumer();
while(1) {
Mat *frame = NULL;
consumer.getVideoFrame(frame);
if(frame == NULL) {
cout << "Null frame" << endl;
continue;
}
if(!frame->empty() && frame->rows > 0 && frame->cols > 0) {
imshow("Test",*frame);
waitKey(10);
frame->release();
}
}
}
I am completely out of ideas and have tried every single thing I knew or found on my researches.
EDIT : Added frame->release() in order to free the allocation, still same issue.
There is a problem in your matrix initialization... Specifically in here:
mat = new cv::Mat(rows,cols,type,(void *)decoded_data.data());
That one is this constructor
Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)
which in the documentation says the following about the *data parameter
data Pointer to the user data. Matrix constructors that take data and
step parameters do not allocate matrix data. Instead, they just
initialize the matrix header that points to the specified data, which
means that no data is copied. This operation is very efficient and can
be used to process external data using OpenCV functions. The external
data is not automatically deallocated, so you should take care of it.
This means that as soon it goes out of scope (the function exits) the string which you created (decoded_data) will exit and the data will be deallocated by the string, and then your cv::Mat will have a reference to a data that is not valid anymore...
You can always initialize the matrix with something like
cv::Mat(rows,cols,type)
and then use something like std::memcpy or similar to copy the data to the mat.data member. Actually, AFAIK it is not needed to pass byte to string and then to mat which is casted to void and then to uchar....
try something like:
mat = cv::Mat(rows,cols,type);
std::memcpy(&decodedBytes[0], mat.data, decodedBytes.size());
Just a small warning for this solution, you need to do a check that decodedBytes is not empty and that mat.data has enough space to receive all the contents of decodedBytes. To do this check just make sure:
// size in bytes to copy == size of the allocated data of mat in bytes
decodedBytes.size() == (mat.elemSize() * mat.rows * mat.cols)
A couple of remarks more that may not be an issue now, but may bite you later:
Do not use cv::Mat pointers... The behaviour of cv::Mat is already like a smart pointer.
Beware of the casting/copy of data from sign to unsign and viceversa :) I think now it is done correctly, but this may become a problem later.

C++ Class Variable not updating

I'm trying to code a counter for a class I made in c++.
I'm passing an amount of time, deltaT, to a method of the Wake class, which does simply adds it onto the value already stored by a variable in the class. The code is:
void checkPlayerWakes(int deltaT){
for(size_t i = 0; i < game.getPlayer().getWakes().size(); i++){
Wake& w = game.getPlayer().getWakes().at(i);
w.age(deltaT);
}
}
However, the timer which is meant to be increasing, is remaining at 0.
The code to change the timer is:
void Wake::age(int millis) {
cout << "Updating : " << currentLife;
this->currentLife += millis;
setAlpha(((double)currentLife)/((double)lifeTime));
cout << " " << currentLife << endl;
}
E.g.
first current life: 0
second current life: 16
I know that if I were to use
Wake w = something
w.age(deltaT)
it wouldn't work because "w" would just be a copy of the object. However, that's clearly NOT my problem here? Also game.getPlayer() also returns a reference, a PLAYERSHIP&.
Last time I had a similar problem, it was solved by calling and returning references instead of just the ClassName. Am I still doing something wrong?
getWakes() needs also to return a reference, and should return vector& as opposed to vector.
I'm adding this here to make sure that this question is marked as answered.

How do you determine what kind of node you are dealing with in yaml-cpp?

I'm reading the tutorial code here: https://code.google.com/p/yaml-cpp/wiki/Tutorial
One example goes like this:
YAML::Node primes = YAML::Load("[2, 3, 5, 7, 11]");
for (YAML::const_iterator it=primes.begin();it!=primes.end();++it) {
std::cout << it->as<int>() << "\n";
}
And the next like this:
YAML::Node lineup = YAML::Load("{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun}");
for(YAML::const_iterator it=lineup.begin();it!=lineup.end();++it) {
std::cout << "Playing at " << it->first.as<std::string>() << " is " << it->second.as<std::string>() << "\n";
}
However, if you swap the YAML files between these two cases, you will get an error, as you are accessing a map iterator for a sequence or vice versa:
terminate called after throwing an instance of 'YAML::InvalidNode'
what(): yaml-cpp: error at line 0, column 0: invalid node; this may result from using a map iterator as a sequence iterator, or vice-versa
For an arbitrary YAML input, how can I determine whether I am dealing with a sequence or a map in the loop (ie whether I should be using ->first or not) without using a try/catch block?
I tried looking for the documentation, but I could not find it.
UPDATE:
This is what I am trying to do:
YAML::Node config = YAML::LoadFile(filename);
for (YAML::const_iterator it=config.begin();it!=config.end();++it) {
if (it->Type() == YAML::NodeType::Map) { // exception
std::cout << it->first.as<std::string>();
} else if (it->Type() == YAML::NodeType::Sequence) {
std::cout << it->as<std::string>();
}
}
But when I run the code I get the exception as above. It compiles fine.
I am using the yaml-cpp which comes with ubuntu 14.04 (0.5.1).
You can either
switch (node.Type()) {
case Null: // ...
case Scalar: // ...
case Sequence: // ...
case Map: // ...
case Undefined: // ...
}
or query explicitly, e.g.:
if (node.IsSequence()) {
// ...
}
(I added this bit to the Tutorial.)
Edit: In your specific example, you should check config.Type() before you iterate, not the type of any of the nodes during your iteration.

Disappearing contents of std::vector<std::string>

I have a vector of strings which are changing its contents for no apparent reason. Can't really explain what is going on. Sorry for a long listing, but it's really bugging me.
I have a GUI application which loads some files and uses a reader object which state can be set by using a parse(int argc, char* argv[]) method. The arguments are set in a dialog by checking various boxes and entering values. Here is a struct I use to hold the data from the dialog:
struct PointFilter
{
PointFilter(): argc(0) {};
~PointFilter() {};
int argc;
std::vector<std::string> args;
};
This struct is a member of the dialog class and after pressing ok button its populated with appropriate values. The values are taken from text boxes on the dialog into a stringstream and then pushed back into a std::vector:
class AdvancedLoadDialog
{
public:
AdvancedLoadDialog(const Glib::RefPtr<Gtk::Builder>&);
~AdvancedLoadDialog();
PointFilter get_point_filter()
{
return this->point_filter;
}
private:
PointFilter point_filter;
void on_ok_btn_clicked();
void AdvancedLoadDialog::on_ok_btn_clicked()
{
std::stringstream filter_stream;
// filter_stream << some_values_from_textboxes ...
std::vector<std::string> args;
std::string arg;
// we need a dummy first argument to emulate the command line
args.push_back("filter");
while (filter_stream >> arg)
{
args.push_back(arg);
}
point_filter.argc = args.size() > 1 ? args.size() : 0;
point_filter.args = args;
advanced_load_dialog->hide_all();
}
Everything works fine till this point and we have an AdvancedLoadDialog object with point_filter member which holds our arguments. Now in a separate window I take the point_filter object and pass it to a constructor of LoadWorker class, which loads the files and also has a PointFilter member.
load_worker = new LoadWorker(..., advanced_load_dialog->get_point_filter())
And then:
LoadWorker::LoadWorker(..., PointFilter pf) :
point_filter (pf)
All well and good. Now in the LoadWorker::run() function I take the arguments from the point_filter, convert them into std::vector and pass them them to the `parse(int argc, char* argv[]) function I need.
void LoadWorker::run()
{
std::cout << "LoadWorker::file_filter contents: \n"
<< "point_filter.argc: " << point_filter.argc << "\n"
<< "point_filter.args: " << std::endl;
for (int i = 0; i < point_filter.argc; ++i)
std::cout << point_filter.args[i] << std::endl;
// ...
if (point_filter.argc != 0)
{
std::cout << "Using filter: " << std::endl;
std::vector<char*> argv;
for (std::vector<std::string>::const_iterator it = point_filter.args.begin();
it != point_filter.args.end(); ++it)
{
argv.push_back(const_cast<char*>(it->c_str()));
}
argv.push_back(0);
for (int i = 0; i < point_filter.argc; ++i)
{
std::cout << argv[i] << std::endl;
}
if (!lasreadopener.parse(point_filter.argc, &argv[0]))
{
send_message("Error parsing filter parameters.");
sig_fail();
return;
}
}
}
Now this works... once. You can notice that the arguments are printed twice, first as elements of LoadWorker::point_filter.args vector and then as elements of the vector<char*> argv. If I set the filter and then press the load button it all works. If I then try to load another file, without changing AdvancedLoadDialog::point_filter at all, the arguments are disappearing. Here's an example output trying to load two files in a row.
LoadWorker::file_filter contents: point_filter.argc: 6
point_filter.args: filter
-clip_z_above 12
-keep_intensity 11 222 Using filter: filter
-clip_z_above 12
-keep_intensity 11 222 LoadWorker::file_filter contents: point_filter.argc: 6 point_filter.args: filter clip_z_above 2
keep_intensity 1 22 Using filter: filter
// 6 blank lines here
To make it even more odd, during the second run each string except the first one in point_filter.args is missing the first character and in the argv they are all empty.
Any clues whatsoever?
Be very, very cautious about doing things involving std::string::c_str as you are doing here:
argv.push_back(const_cast<char*>(it->c_str()));
If you want to keep the values provided by c_str, you should copy them into a new container first.
If cplusplus.com is to be trusted (which is not always the case),
the values in this array should not be modified in the program and are only guaranteed to remain unchanged until the next call to a non-constant member function of the string object
Though I can't immediately put my hands on any more useful information from other sources.
In AdvancedLoadDialog, try pushing an allocated version of arg rather than an automatic version. You appear to be pushing a reference to a variable that will be destructed upon leaving AdvancedDialogLoad.

RapidJSON library getting a value inside an array by its index

{"hi": "hellow",
"first":
{"next":[
{"key":"important_value"}
]
}
}
Accessing RapidJSON inside array:
this works: cout << "HI VALUE:" << variable["hi"].GetString() << endl; this will output: hellow as expected, the problem is to access inside values like if I want to get "Important_Value", I tried something like this: cout << "Key VALUE:" << variable["first"]["next"][0]["key"].GetString() << endl ; but this doesn't work, I want to be able to get the "important_value" by the first item of the array, and in this case it's the [0] that is causing error.
How do I do to get it by its index?
I hope it's clear my explanation.
Thanks in advance.
JSON
{"hi": "hellow", "first": {"next":[{"key":"important_value"} ] } }
Code:
rapidjson::Document document;
if (document.Parse<0>(json).HasParseError() == false)
{
const Value& a = document["first"];
const Value& b = a["next"];
// rapidjson uses SizeType instead of size_t.
for (rapidjson::SizeType i = 0; i < b.Size(); i++)
{
const Value& c = b[i];
printf("%s \n",c["key"].GetString());
}
}
Will print important_value
[Update]
By clever work of contributors, RapidJSON can now disambiguate literal 0 from string. So the issue is no longer happens.
https://github.com/miloyip/rapidjson/issues/167
The problem, as mjean pointed out, the compiler is unable to determine whether it should call the object member accessor or the array element accessor, by literial 0:
GenericValue& operator[](const Ch* name)
GenericValue& operator[](SizeType index)
Using [0u] or [SizeType(0)] can workaround this.
Another way to cope with this problem is stop using overloaded version for operator[]. For example, using operator() for one type of access. Or using normal functions, e.g GetMember(), GetElement(). But I do not have preference on this right now. Other suggestions are welcome.
I noticed this in the tutorial.cpp file;
// Note:
//int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
int z = a[0u].GetInt(); // This works too.
I didnt test it but you may want to try one of these;
variable["first"]["next"][0u]["key"].GetString()
variable["first"]["next"][SizeType(0)]["key"].GetString()
auto value = my_array[rapidjson::SizeType(index)].GetFoo();
// replace GetFoo with the type of element you are retrieving, e.g. GetString, GetObject
If you want to access it with brackets, then you can use the following:
int i=0;
cout<<"Key VALUE:"<<variable["first"]["next"][i]["key"].GetString()<<endl ;
Output: Key VALUE:important_value
It worked for me.