I faced an issue, which I can not explain when converting QByteArray to const char* not inline. Here is an example:
QString string1("ABCDEFGHI");
const char* stringData1 = string1.toUtf8().constData();
qDebug() << "String:" << string1 << "\nbytearray:" << string1.toUtf8()
<< "\ndata immediate:" << string1.toUtf8().constData() << "\ndata stored:" << stringData1;
QString string2("ABCDEFGHJ");
const char* stringData2 = string2.toUtf8().constData();
qDebug() << "String:" << string2 << "\nbytearray:" << string2.toUtf8()
<< "\ndata immediate:" << string2.toUtf8().constData() << "\ndata stored:" << stringData2;
I get the following output:
String: "ABCDEFGHI"
bytearray: "ABCDEFGHI"
data immediate: ABCDEFGHI
data stored:
String: "ABCDEFGHJ"
bytearray: "ABCDEFGHJ"
data immediate: ABCDEFGHJ
data stored: ABCDEFGHJ
The output of data stored is not guaranteed to be wrong in case 1, but correct in case 2. I can swap cases 1 and 2, and the result will be the same - wrong in case 1, but correct in case 2.
Inline conversion seems to work just fine.
Do you see any issues with conversion from QByteArray to const char* if a const char* variable is used to store the result?
toUtf8 returns an object whose lifetime ends at the end of the expression.
constData returns a pointer into this temporary object.
Thus, you're using dangling pointers and the behaviour is undefined.
You need to extend the lifetime of the converted string:
QString string1("ABCDEFGHI");
QByteArray utfString = string1.toUtf8();
const char* stringData1 = utfString.constData();
This call string1.toUtf8().constData() consists of two consequential ones: QString::toUtf8()which produces a temporary QByteArray, and QByteArray::constData() which returns a pointer to a temporary object, which eventually getting destroyed.
The way I used to get a QString variable, convert it to QByteArray and finally const char* is this:
QString var1 = ui->lineEdit->text().toUtf8();
QByteArray ba = var1.toLocal8Bit();
const char *var1final = ba.data();
The value of QString is collected by Ui, in lineEdit.
Related
I am a C# developer and I find strange that when I run the following code in C++:
std::string original = "Hello";
std::string st = original + "World";
const char *c = st.c_str();
const char *c2 = (original + "World").c_str();
std::cout << "c = '" << c << "'" << std::endl;
std::cout << "c2 = '" << c2 << "'" << std::endl;
I get the following output:
c = 'HelloWorld'
c2 = ''
In C# a similar construct will result in c and c2 having the same value ("Hello World"). My guess would be that the scope of the result of (original + "World") ends on the right ), so c_str() is called on an invalid input. Is that correct? Is there a better way of achieving this other than creating variables to hold temporary results?
Thanks!
My guess would be that the scope of the result of (original + "World") ends on the right ), so c_str() is called on an invalid input. Is that correct?
Not quite, but close. c_str() itself is fine, but that pointer become invalid after the end of the statement, so using c2 afterwards leads to UB.
Is there a better way of achieving this other than creating variables to hold temporary results?
You can assign it to const reference:
const std::string &ref = original + "World";
const char *c2 = ref.c_str();
But I don't think that any better than creating variable.
'c2' here is initialized with a pointer into a temporary object that ceases to exist at the semicolon. Therefore this is undefined behavior. You'll need to use an intermediate variable:
const auto temp(original + "World");
const char* c2 = temp.c_str();
I need to convert a Str to char* but I sometimes lose a part of the string.
For example:
str: "/Users/seb/Pictures/Photos/20141009 - Aulani - Hawaii/20141009_083318_Richtone(HDR).jpg"
char*: /Users/seb/Pictures/Photos/20141009 - Aulani - Hawaii/20141009_083318_Ri
I'm using the code below:
void TreeWidget::CopyFilesFromLocal(QStringList pathList, QTreeWidgetItem * item) {
QString fileelt;
uint32_t Folder_id = INVALID;
MyTreeWidget* myItem = dynamic_cast<MyTreeWidget*>(item);
uint32_t destination_id = myItem->mtp_item_id;
item->setExpanded(true);
qDebug() << "**************************************";
qDebug() << "Send to PULS Start";
qDebug() << "Start of Loop to copy files";
foreach(fileelt, pathList) {
char *txt = NULL;
// char *isFileName = NULL;
qDebug() << "str: " << fileelt;
txt = strdup(m_device.convertQStr2char(fileelt));
qDebug() << "char*: " << txt;
Here is the api I use.
char *PulsDeviceMngr::convertQStr2char(QString str) {
return const_cast<char*>(std::string(str.toUtf8().constData() ).c_str());
}
Any idea ?
The pointer you return form convertQStr2char points to the internal buffer of the temporary std::string which is destroyed after the return. You thus use a dangling pointer and have undefined behavior.
Note that changing the data pointed to by std::string::c_string() through said pointer also is UB. Your const_cast is a very bad idea because it would allow exactly this even if you got the lifetime right.
You could do this instead (includes a couple of unnecessary copies, but get it working first, then worry about the rest):
char *PulsDeviceMngr::convertQStr2char(QString str) {
return strdup(std::string(str.toUtf8().constData() ).c_str());
}
Then do not forget to free the buffer. But it would probably be better to just return the std::string by value and then use .c_str() outside of your conversion function. This way, you do not need to use the non-C++ strdup and do not need to manage memory by hand, which would be error prone anyway.
You don't need an extra method
txt = strdup(fileelt.toUtf8().constData());
will work fine.
Is there any explanation in the standard for the below behavior?
The following code:
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
ostringstream os1;
ostringstream os2;
os1 << 1 << " " << 2;
os2 << 1 << " " << 2 << " " << 3;
const char *p = os1.str().c_str();
cout << os2.str() << endl;
cout << p << endl;
return 0;
}
displays the output:
1 2 3
1 2 3
However, I would expect it to display:
1 2 3
1 2
It looks like os1 object is somehow influenced by os2, if I remove the os2.str() call, example behaves correctly.
I have tried the example if Solaris Studio 12.2 and G++ 4.8.1 and both behave in the same way.
Thanks for your help!
const char *p = os1.str().c_str();
Here is the problem, in the above line.
os1.str() returns a temporary string object by copying the internal string buffer. And you're taking .c_str() of the temporary object, which gets destroyed at the end of the full expression. The result is, p points to the destroyed object when you take it to print using std::cout.
That is, your program invokes undefined behavior (UB).
Try this:
auto s = os1.str();
const char *p = s.c_str(); //s is not a temporary object anymore!
Now it gives correct output (and this is your code — luckily even coliru gives the same output as you observed on your machine. Note that this output is not guaranteed though precisely because the code invokes UB.).
I think the issue has to do with retaining the pointer returned by c_str().
ostringstream::str() is returning a temporary string object, and you are saving a pointer to it's internal char array. But once that line has executed, the returned string object will be deleted. So your pointer will be invalid.
If you want to keep a c_str pointer around for some reason, you would need to also keep a copy of the string:
string s = os1.str();
const char *p = s.c_str();
cout << os2.str() << endl;
cout << p << endl;
The answer to this question is here:
stringstream, string, and char* conversion confusion
stringstream.str() returns a temporary string object that's destroyed at the end of the full expression. If you get a pointer to a C string from that (stringstream.str().c_str()), it will point to a string which is deleted where the statement ends.
I have a subclass of QTableWidget with the following code:
connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(pushCellChange(int, int)), Qt::QueuedConnection);
...
void MyTableView::pushCellChange(int row, int column)
{
QString text(item(row, column)->text());
QByteArray data = text.toAscii();
cout << data.length() << endl;
const char* cellData = text.toAscii().constData();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
}
When I change the upper-right cell to anything this outputs:
2
Cell (0, 0) changed to: ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌░▬∟C▌▌
However, while this corrupt data is spewed out on the console, the table widget itself seems to behave normally and shows the correct string. Does anyone know what is going on here?
The call toAscii() is storing the QString's data to a QByteArray. In your code, you do this twice:
QByteArray data = text.toAscii();
const char* cellData = text.toAscii().constData();
_____________^ <-- temporary QByteArray
The const char* is actually pointing to the data within a temporary variable, which goes out of scope at the semicolon, at which point the pointer becomes invalid. If instead you were to make use of the local variable data, you'd be OK:
const char* cellData = data.constData();
___^ <-- still-in-scope QByteArray
Alternatively, you can do this all in-line with the cout and the data will still be valid when it is copied to the output stream:
cout << "Cell ("<<row<<","<<column<<") changed to: " << text.toAscii().constData() << endl;
std::string cellData = text.ToStdString();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
That should work fine. As for why toAscii doesn't work, I have no clue.
If it's just about the console output, you could also use qDebug() (available after #include <QDebug>) and pass the QString directly:
void MyTableView::pushCellChange(int row, int column)
{
qDebug() << item(row, column)->text().length();
qDebug() << "Cell (" << row << ", " << column << ") changed to: "
<< item(row, column)->text();
}
This way, you don't have to mess with data conversion …
I have a static method that should return the next available id. Several static members in other classes call this function, so each gets a different id assigned. However, when I am printing the assigned values I dont get "id0", "id1" but just a symbol like "*". I'm using this code:
int A::i = 0; //static member
std::string A::id()
{
std::stringstream sst;
sst<< "id" << A::i;
i++;
return sst.str(); //i've tried to return a const char* too, but doesnt work either
}
//assigning id's in several classes like this:
const char* B::id = A::id().c_str();
const char* C::id = A::id().c_str();
//printing them in the main function:
std::cout << B::id << " " << C::id << "\n";
I dont understand why the code above doesnt work. When I am executing the following code the expected result "id10" is printed:
static std::string gt()
{
std::stringstream ss;
ss << "id" << 10;
return ss.str();
}
Look at
const char* C::id = A::id().c_str();
You are creating a new id string, then you take a pointer to its data (as a c-string), and inmediately after that the temporary string to which contents you are pointing gets destroyed. Simple answer: either stick to std::string or to plain int ids.