const char * overwritten in next iteration of while loop - c++

First of all, everything is happening in an if{} statement in a do{}while loop. I have a struct that contains some const char pointers. I'm trying to get info into a temp struct with new string values each iteration, then push this struct into a vector of said structs, so that when the function exits, the vector is populated with different struct objects.
do{
if()
{
sound_device_t newDevice; //<--- Why is this the same mem address each iteration?
//I thought it would be destroyed when it's scope was (the if block)
const char * newPath;
someFunction(&newPath); //puts a string into newPath
newDevice.firstString = newPath; //<-- This works.
QString otherPath(const char *);
//...some QString manipulation...//
newDevice.secondString = otherPath.toLocal8Bit().data(); //<--this doesn't
vector_of_structs -> push_back(newDevice);
}
}while (...)
I was under the impression that push_back copied the argument struct's values into its own version. Why is the QString giving me problems? I am using QString because it has some good string manipulation functions (i.e. insert and section), but I'll exchange it if I need to for something that works.
I have also tried putting the QString's data into a char * and then strcpy'ing it into the struct, but that has the same result. Every iteration rewrites newDevice.secondString.

QByteArray::data() is only valid so long as the ByteArray is unchanged. Destroying the temporary is changing.
In other words after the semi colon of the line newDevice.secondString = otherPath.toLocal8Bit().data(); the QByteArray returned by toLocal8Bit is destroyed and the stored array deleted.

There are a couple of issues with your code:
if statement without condition (!)
invalid construction: QString otherPath(const char *); You probably want an "otherPath" variable there similarly to "newPath".
You are mixing qt types with std containers. You should take a loo at QStringList.
Needless pointer usage: newDevice.secondString = otherPath.toLocal8Bit().data();
The last one is especially critical since you destroy otherPath before the next iteration. The solution is to use a deep copy in there.
I would write something like this:
do {
if(cond) {
sound_device_t newDevice;
const char * newPath;
someFunction(&newPath);
newDevice.firstString = newPath;
// Get other path
QString otherPath(otherPath);
//...some QString manipulation...
newDevice.secondQString = otherPath;
// or: strcpy( newDevice.secondString, otherPath.toLocal8Bit().data());
vector_of_structs->push_back(newDevice);
}
} while (...)
That being said, depending on what you are trying to do, QtMultiMedia might be better used overall for your sound device purpose. As long as dbus goes, there is also a QtDBus add-on module.

Thanks for all the help guys. I got the original code working with just one tweak:
newDevice.secondString = otherPath.toLocal8Bit().data();
should be changed to
newDevice.secondString = strdup(otherPath.toLocal8Bit().data());
This does the buffer allocation directly, as #ratchet freak was suggesting. strcpy() doesn't work because it still connects newDevice.secondString with the QByteArray, just like toLatin1().data() does.

Related

How to efficiently move underlying data from std::string to a variable of another type?

EDIT: Sorry everyone, I don't think this toy example really reflected my problem. What I should have asked is if there is a way to release a std::string object's buffer. There is not, and that makes sense. Thanks!
Suppose I have the following (broken) code:
void get_some_data(MyCustomContainer& val)
{
std::string mystr = some_function();
val.m_data = &mystr[0];
}
This won't work, because the memory pointed by mystr is freed at the end of get_some_data, and the memory referenced by val.m_data will be invalid.
How can I tell a std::string "Don't free your memory buffer at your destructor!" ? I don't want to copy the data. The MyCustomerContainer object will handle the memory free-ing at its destructor.
You cannot do this without breaking the rules. The std::string class is not allowed to release its ownership explicitly. In fact, a std::string might not even have any memory allocated due to SBO optimization:
std::string str1 = "not allocating";
std::string str2 = "allocating on the heap, the string is too large";
This behavior is completely platform- and implementation-dependent. If a string doesn't allocate its buffer on the heap, the data is placed on the stack, which doesn't need de-allocation.
{
std::string str1 = "not allocating";
} // no buffer freed
So even if there were a way to tell the string not to de-allocate its buffer, there is no way to tell if the buffer is managed on the heap or not.
Even if there were a way to tell if the string uses the stack, you'd have to allocate a buffer in place as a class member and copy its content.
The idea of transferring a string's data and stealing its ownership over that string's memory resource is fundamentally broken as you can't get away without copying, simply because there might be no ownership to steal.
What I recommend is for you to copy the string content in all cases if you don't want to change how MyCustomContainer works:
void get_some_data(MyCustomContainer& val)
{
std::string mystr = some_function();
val.m_data = new char[mystr.size()];
std::memcpy(val.m_data, mystr.data(), mystr.size());
}
In contrast, if you allow MyCustomContainer to store a std::string, you could actually get away without copying when a buffer is allocated by moving the string:
void get_some_data(MyCustomContainer& val)
{
// let m_data be a std::string
val.m_data = some_function();
// The above is equivalent to this:
// std::string mystr = some_function();
// val.m_data = std::move(mystr);
}
Moving a string will invoke move assignation. With move assignation, the string implementation will transfer the ownership of the mystr's buffer into m_data. This will prevent any additional allocation.
If mystr didn't allocate, then the move assignment will simply copy the data (so no allocation there, either).
The right way to fix this problem is:
class MyCustomContainer {
public:
std::string m_data;
};
void get_some_data(MyCustomContainer& val) {
val.m_data = some_function();
}
The get_some_data could even be made into a member function, which would make the usage even easier at the callsite, and perhaps allow m_data to be private instead of exposed.
If .m_data is an std::string you can take advantage of std::string's move-assignment operator:
val.m_data = std::move(mystr);
If m_data is not an std::string you are pretty much out of luck, the internal buffer is inaccessible (as it should be).
No, you cannot. std containers will only give up their managed memory (and then only sometimes) to std containers of the same type.
For string this would be impossible regardless, as most implementations do a short string optimization and store short strings internally.
You could throw the std string into a global buffer somewhere and reap it at cleanup, but that gets insanely complex.
If you want you can use this code that causes Undefined Behavior, so it should not be used, but if you are working on some toy project of your own that will be quickly abandoned you can see if it works for you.
// REQUIRES: str is long enough so that it is using heap,
// std::string implementation does not use CoW implementation...
// ...
char* steal_memory(string&& str){
alignas(string) char buff[sizeof(string)];
char* stolen_memory = const_cast<char*>(str.data());
new(buff) string(move(str));
return stolen_memory;
}
If you want to handle short string you should add malloc and copy from buffer for that case.
Main idea here is to use placement new that takes the ownership from our input string, and not calling the destructor on string in buff. No destructor means no calls to free, so we can steal memory from the string.
Unfortunately const_cast is UB in this case so like I said you should never use this code in serious code.
You can do mystr static
void get_some_data(MyCustomContainer& val)
{
static std::string mystr;
mystr = some_function();
val.m_data = &mystr[0];
}
but, in this way, you have only one mystr for all get_some_data() calls; so
get_some_data(mcc1);
get_some_data(mcc2);
// now both `mcc1.m_data` and `mcc2.m_data` point to the same value,
// obtained from the second `some_function()` call
If you can compile-time enumerate the calls to get_some_data(), you can differentiate your mystr using a template index
template <std::size_t>
void get_some_data(MyCustomContainer& val)
{
static std::string mystr;
mystr = some_function();
val.m_data = &mystr[0];
}
get_some_data<0U>(mcc1);
get_some_data<1U>(mcc2);
// now `mcc1.m_data` and `mcc2.m_data` point to different values

Casting to void* with potentially sketchy behavior

I have been trying to fix a potentially sketchy use of void* casting in a task scheduling application for weeks now. Note that I am NOT getting a compiler error, but the scheduling program crashes after a few hours (for some unknown reason). Consider the following code snippets from the program:
In main:
CString* buffer = new CString(temp);
parameters.set("jobID", (void *) buffer);
runJob(parameters);
Also, VGridTaskParam class is as follows:
class VGridTaskParam{
map<CString, void *> p; // maps from CString to a pointer that is not known
public:
void * get(CString name){
return p[name]; // returns the map value of the name which is an unknown pointer
}
void set(CString name, void * data){
p[name] = data; // sets the mpa value given a particular key
}
};
Snippet of some work in runJob(VGridTaskParam parameters) function is:
void runJob(VGridTaskParam parameters)
{
CString JIDstr; // job ID string
//get job ID as CString
CString* pJID = (CString*)parameters.get("jobID");
JIDstr = CString(*pJID);
delete pJID; ******************************
}
Some questions: does the last delete line (marked with several asterisks) delete the memory allocation created in the main program? Is my use of void* casting warranted in this situation. Note that whenever I run a job, I spawn a new thread. Can someone suggest a potential fix to this problem? What should I look at to fix this problem?
does the last delete line (marked with several asterisks) delete the memory allocation created in the main program?
Yes.
Is my use of void* casting warranted in this situation?
No, that is superfluous. Any pointer can be cast to void* without the explicit cast.
Can someone suggest a potential fix to this problem? What should I look at to fix this problem?
I can't suggest a fix without an MCVE.
A few possible issues:
what will happen if you write twice to same key? This will cause a memory leak.
there are few possible solutions, like:
void set(CString name, void * data){
if(p[name]!=NULL)
delete p[name];
p[name] = data; // sets the mpa value given a particular key
}
Another thing: Are you running multi-threaded or single threaded? for multi-threaded you should synchronize the get and set methods to prevent pointer changes in a middle of action.
And finally, what happen if key not found? you should check the returned pointer. also remove from the set or null it after usage.
void runJob(VGridTaskParam parameters)
{
CString JIDstr; // job ID string
//get job ID as CString
CString* pJID = (CString*)parameters.get("jobID");
if(pJID){
parameters.set("jobID",NULL);
JIDstr = CString(*pJID);
delete pJID; ******************************
}
}
I see two things that looks a bit surprising to me.
1) runJob takes parameters of type VGridTaskParam by value. Maybe you want a reference instead. That can't explain the crash, though.
2) You never seem to remove anything from the map even though you delete the memory associated with the pointer. So there is a risk that you'll use the pointer value later on. Either as a dereference or as a double delete.
3) You don't implement any check for the key being present in the map.
Your delete is correct. It deletes an allocated block of memory of the size of the pointer's type at the pointer's address. So when you allocate a CString with new you will delete the exact same amount of memory.
The hang up is when you delete unallocated memory. There are several ways I could see this happening in your current code:
runJob requests an key not in the map (this will return a default initialized CString* as the newly created value.)
You call runJob on a previously deleted item in the map (this value would already be deallocated and deleting it again would be illegal.)
We can't see all your code but if there is the potential to delete these pointers elsewhere there could also be a double cleanup problem there.
You should code your map more defensively, for example:
const void* get(const CString& name) const {
return p.find(name) == p.cend() ? nullptr : p[name]; // returns the map value of the name which is an unknown pointer
}
void set(const CString& name, void* data) {
void* toOverwrite = get(name);
if(toOverwrite != nullptr) {
delete toOverwrite;
}
p[name] = data; // sets the mpa value given a particular key
}
void remove(const CString& name) {
if(p.find(name) != p.end()) {
p.erase(name);
}
}
In your function you'd need to change to testing if the return of get was a nullptr before operating on the result, and rather than delete you'd need to call remove. This keeps all modification of p local to the class, thereby guaranteeing correct maintenance of the map.

mechanism that make a string empty after std::move() it

I have some confusion about how a std::move() really empty something.
I write some code:
int main()
{
string str1("this is a string");
std::cout<<std::boolalpha<<str1.empty()<<std::endl;
string str2(std::move(str1));
cout<<"str1: "<<str1.empty()<<endl;
cout<<"str2: "<<str2.empty()<<endl;
}
The output is:
false
true //this mean the original string is emptied
false
Why is the original string emptied every time?
I have read some meterial about the move semantics,including the original proposal of it(this one), which said:
The difference between a copy and a move is that a copy leaves the source unchanged. A move on the other hand leaves the source in a state defined differently for each type. The state of the source may be unchanged, or it may be radically different. The only requirement is that the object remain in a self consistent state (all internal invariants are still intact). From a client code point of view, choosing move instead of copy means that you don't care what happens to the state of the source.
So,according to this words, the original content of the str1 above should be some kind of undefined. But why is that every time it have been move(), it is emptied? (Actually I have test this behavior on both std::string and std::vector but the result is the same.)
To learn more, I define my own string class to test, as bellow:
class mstring
{
private:
char *arr;
unsigned size;
public:
mstring():arr(nullptr),size(0){}
mstring(char *init):size(50)
{
arr = new char[size]();
strncpy(arr,init,size);
while(arr[size-1] != '\0') //simply copy
{
char *tmp = arr;
arr = new char[size+=50]();
strncpy(arr,tmp,50);
delete tmp;
strncpy(arr-50,init+(size-50),50);
}
}
bool empty(){ return size==0;}
}
Doing the same thing:
int main()
{
mstring str("a new string");
std::cout<<std::boolalpha<<str.empty()<<std::endl;
mstring anotherStr(std::move(str));
std::cout<<"Original: "<<str.empty()<<std::endl;
std::cout<<"Another: "<<anotherStr.empty()<<std::endl;
}
The output is:
false
Original: flase //mean that the original string is still there
Another: false
Even I add a move constructor like this:
mstring(mstring&& rvalRef)
{
*this = rvalRef;
}
The result is still the same.
My question is: why is the std::string get emptied but my self-defined isn't?
Because that's how the std::string move constructor is implemented. It takes ownership of the old string's contents (i.e. the dynamically-allocated char array), leaving the old string with nothing.
Your mstring class, on the other hand, doesn't actually implement move semantics. It has a move constructor, but all it does is copy the string using operator=. A better implementation would be:
mstring(mstring&& rvalRef): arr(rvalRef.arr), size(rvalRef.size)
{
rvalRef.arr = nullptr;
rvalRef.size = 0;
}
This transfers the contents to the new string and leaves the old one in the same state that the default constructor would have created it. This avoids the need to allocate another array and copy the old one into it; instead, the existing array just gets a new owner.
So,according to this words, the original content of the str1 above should be some kind of undefined.
There is absolutely nothing about what the state should be. The specification says what the state could be: anything defined enough that it can be destroyed or assigned new value.
Empty qualifies as anything, so the state can be empty.
It also makes most sense in this case. A string is, essentially, something like
class string {
char *_M_data;
size_t _M_size;
size_t _M_alloc;
public:
...
}
where the _M_data is allocated with new and must be deleted with delete (this is customizable with the allocator parameter, but the default allocator does just that).
Now if you don't care about the state of the source, the fastest thing that can be done is to assign the buffer to the destination and replace the buffer with nullptr in the source (so it does not get deleted twice). A string with no buffer is empty.

c++ constructor malfunctioning

I am trying to program a qt widget application which deals with linked list of nodes, the node contains 3 char* data member and 2 int members and a "next" pointer of "node" type,
my issue is the char* members in nodes of the linked list are getting saved same as the third char* member, I tried using debugger and found out that
the length of all the 3 ints i.e. lentitl,lenpub,lenpub are initialized to same value, and all the 3 char* members are getting same value,
the node constructor is as follows
node::node(char* titl,char* auth,char* pub,int pri,int stockp)
{
int lentitl,lenauth,lenpub;
lenpub=strlen(pub);
lentitl=strlen(titl);
lenauth=strlen(auth);
title=new char[lentitl+1];
author=new char[lenauth+1];
publisher=new char[lenpub+1];
strcpy(title,titl);
strcpy(author,auth);
strcpy(publisher,pub);
price=pri;
stockposition=stockp;
next=NULL;
}
the node functions if called from another class function named "addbook",and addbook is called from mainwindow.cpp, the functions calls for addbook is as follows
void MainWindow::on_addbook_clicked()
{
char *titl,*auth,*pub;
int pri,stockp;
titl=ui->title->toPlainText().toLatin1().data();
auth=ui->author->toPlainText().toLatin1().data();
pub=ui->publisher->toPlainText().toLatin1().data();
pri=ui->price->toPlainText().toInt();
stockp=ui->stockposition->toPlainText().toInt();
p.addbook(titl,auth,pub,pri,stockp);
}
and the function call for node is as follows
void shop::addbook( char *titl, char *auth, char *pub, int pri, int stockp)
{
node *p=new node(titl,auth,pub,pri,stockp);
if(start==NULL)
{
start=p;
end=p;
}
else
{
p->next=start;
start=p;
}
}
the zip of whole project is here
and here is the link to the ouput
the screen shot of the output is
as you can see in the image,string entered at "publisher" textedit is getting set to all 3 char* of the node,
can anyone explain me why is this happening?
titl=ui->title->toPlainText().toLatin1().data();
This is probably the issue: toLatin1() returns a new QByteArray which owns its data. You assign the internal data pointer of that QByteArray to titl. However, the QByteArray is only a temporary variable and will get destroyed in the next line of code. When the QByteArray gets destroyed, it will free its data, which means your titl is now pointing to memory that was already freed - i.e. titl points to an invalid memory location.
Suggested solution alternatives:
Use QString instead of char* in your node class, much easier to deal with memory management issues that way
Make sure your QByteArray temporary lives as long as you need the data (until you strcpy the data):
QByteArray titl = ui->title->toPlainText().toLatin1();
QByteArray auth = ui->author->toPlainText().toLatin1();
QByteArray pub = ui->publisher->toPlainText().toLatin1();
pri=ui->price->toPlainText().toInt();
stockp=ui->stockposition->toPlainText().toInt();
p.addbook(titl.data(),auth.data(),pub.data(),pri,stockp);
I'm not expert of Qt but there is something that doesn't sound good to me in terms of C++. Mainly a function in your code is returning a "char * " pointer instead of a "const char*", I'm talking about these lines:
char *titl,*auth,*pub;
int pri,stockp;
titl=ui->title->toPlainText().toLatin1().data();
If the data was directly provided by the title class I expect to obtain a const char* pointer in order to do not be allowed to modify it. The only reason you can handle a char* ( or in other words a well known library is designed to return a non const pointer) is that there is a temporary object or a static buffer in the middle of the calls: toLatin1 or data.
Reading the docs of Qt: toLatin1 is returning a temporary object, a QByteArray.
QByteArray toLatin1 () const
for more information: http://qt-project.org/doc/qt-4.8/qstring.html
So simply modify each string request like:
QByteArray titlArray = ui->title->toPlainText().toLatin1();
titl=titlArray.data();
in that way each string will point to a still existing buffer when you are calling
p.addbook(titl,auth,pub,pri,stockp);

std::vector overwriting final value, rather than growing?

I'm having an issue where using vector.push_back(value) is overwriting the final value, rather than appending to the end. Why might this happen? I have a sample item in the vector, so it's size never hits zero. Below is the code..
void UpdateTable(vector<MyStruct> *Individuals, MyStruct entry)
{
MyStruct someEntry;
bool isNewEntry = true;
for (int i = 0; i < Individuals->size(); i++)
{
if (!(strcmp(Individuals->at(i).sourceAddress, entry.sourceAddress)))
{
isNewEntry = false;
//snip. some work done here.
}
}
if(isNewEntry)
{
Individuals->push_back(entry);
}
}
This let's my first "sample" value stay in, and will allow for just one more item in the vector. When 2 new entries are added, the second overwrites the first, so the size is never larger than 2.
edit: More code, since this is apparently not the issue?
void *TableManagement(void *arg)
{
//NDP table to store discovered devices.
//Filled with a row of sample data.
vector<MyStruct> discoveryTable;
MyStruct sample;
sample.sourceAddress = "Sample";
sample.lastSeen = -1;
sample.beaconReceived = 1;
discoveryTable.push_back(sample);
srand(time(NULL));
while(1)
{
int sleepTime = rand() % 3;
sleep(sleepTime);
MyStruct newDiscovery = ReceivedValue();
if (newDiscovery.lastSeen != -1000) //no new value from receivedValue()
{
UpdateTable(&discoveryTable, newDiscovery);
}
printTable(&discoveryTable);
}
return NULL;
}
I'm going to hazard a guess:
Suppose MyStruct is declared like
struct MyStruct
{
const char *sourceAddress;
// Other Gubbins ...
};
And that ReceivedValue does something like
MyStruct ReceivedValue()
{
static char nameBuffer[MAX_NAME_LEN];
// Do some work to get the value, put the name in the buffer
MyStruct s;
s.sourceAddress = nameBuffer;
// Fill out the rest of MyStruct
return s;
}
Now, every structure you push into your vector has sourceAddress pointing to the same global buffer, every time you call ReceivedValue it overwrites that buffer with the new string - so every entry in your vector ends up with the same string.
I can't be sure without seeing the rest of your code, but I can be sure that if you follow some of the good C++ style suggestions in the comments to your question this possiblity would go away.
Edit for clarification: there's no need to heap allocate your structures, simply declaring sourceAddress as a std::string would be sufficient to eliminate this possibility.
The scope for the items you are pushing into the database is expiring. They're being destructed when you leave the {} in which they were created - and as such the reference to them is no longer valid.
You need to change it from vector<MyStruct> to vector<MyStruct*> (preferably using safe pointers from Boost:: instead of pointers, but you get the idea).
You are creating the item within the (limited) scope and pushing it onto the vector (while the struct is copied, the strings in it are not!) it then reuses the same memory location (most likely if properly optimized) to store the next "new" struct and the one after that and so on and so forth.
Instead, within the limited scope create MyStruct *myObject = new MyStruct and assign its values, then push the pointer to the vector.
Remember to delete all values from the vector before clearing it/destroying it!!
Or, of course, you could use std::string/CString/whatever instead of a char array and avoid the issue entirely by having a safe-to-copy struct.
ComputerGuru's answer works however there in another alternative. You can create a copy constructor and overload operator= for MyStruct. In these operations, you need to copy the actual string into the new struct. In C++, structs are nothing more than classes with default public access instead of default private access. Another alternative is to use std::string instead of char* for the string value. C++ strings already have this behavior.
struct MyStruct {
std::string sourceAddress;
int lastSeen;
int beaconReceived;
};
Seems odd to me: Maybe there is something wrong with the //snip part of the code?
Try to log the size of the vector before and after the push_back call (either in the debugger or using cout) and also have a look at the isNewEntry variable.
Your code looks alright to me. Is it possible that you are not passing the right vector in? What I mean is that the behaviour you describe would appear if somehow your Individuals vector is being reset to its orginal 1-entry state before you tried to add the 3rd entry, then it would appear as if your 2nd entry was being overwritten.
Here is what I mean:
int test_table()
{
string SampleAddresses[] = {"Sample Address 1", "Sample Address 2"};
for (int i = 0; i < 2; i++)
{
// All this work to build the table *should* be done outside the loop; but we've accidentally put it inside
// So the 2nd time around we will destroy all the work we did the 1st time
vector<MyStruct> Individuals;
MyStruct Sample;
Sample.sourceAddress = "Sample Address 0";
Test.push_back(Sample);
// this is all we meant to have in the loop
MyStruct NewEntry;
NewEntry.sourceAddress = SampleAddresses[i];
UpdateTable(Individuals, NewEntry);
}
//Now the table has 2 entries - Sample Address 0 and Sample Address 2.
}
If this was all your code then the problem would be obvious. But it might be concealed in some other pieces of code.