QString and QByteArray memory usage - c++

The QByteArray documentation states that it is to be used when memory conservation is critical. I've been working on a class (FieldName) that keeps an internal store of commonly used QString's so that when two FieldName objects are compared for equality, a quick integer comparison is done.
My thinking was that I could save some memory and gain speed by using QByteArray instead of QString since I only need standard ASCII characters. But when I change out the QString in the following code for QByteArray, my tests show that speed is increased, but memory usage more than doubles. This runs counter to the documentation.
#ifndef H_FIELDNAME
#define H_FIELDNAME
#include <QString>
class FieldName
{
public:
FieldName() : mKey(0) { init(); }
FieldName(const QString& s);
const QString& constString() const;
bool operator==(const FieldName& other) const { return mKey == other.mKey; }
bool operator!=(const FieldName& other) const { return mKey != other.mKey; }
private:
int mKey;
void init();
int findKey(const QString& s);
};
#endif
CPP file:
#include "fieldname.h"
// #include <QMutex> // demo version not thread-safe
#include <QVector>
static QVector<QString*> FieldName__List;
static bool FieldName__FirstCall(true);
FieldName::FieldName(const QString& s)
{
init();
mKey = findKey(s);
}
const QString& FieldName::constString() const
{
return(*FieldName__List.at(mKey));
}
void FieldName::init()
{
if(FieldName__FirstCall)
{
if(FieldName__List.isEmpty())
{
FieldName__List.append(new QString(""));
FieldName__FirstCall = false;
}
}
}
int FieldName::findKey(const QString& s)
{
if(s.isEmpty())
return 0;
int sz(FieldName__List.size());
for(int idx=1; idx<sz; ++idx)
{
if(s == *FieldName_List.at(idx))
return idx;
}
FieldName__List.append(new QString(s));
return(FieldName__List.size() - 1);
}
Can anyone let me know what I may be doing that is causing this to use more memory when I substitute QByteArray for QString in the above class?
Testcode:
QStringList qsl; // filled with 84000 unique English words
FieldName fn;
foreach(QString s, qsl)
{
fn = FieldName(s);
// do stuff here
}

Related

How to show double and integers in a TableView in QT

I have a table with 5 rows and 5 columns. I am trying to insert double numbers and integer numbers. On column 1 and 2 (double numbers) and column 3 and 4 (integer) and last column images.
I am trying to figure out what the error is in the code I wrote:
#ifndef ITEMROI_H
#define ITEMROI_H
#include <QObject>
#include <QString>
class itemRoi
{
public:
itemRoi(int &size, const QString &threeDLocation, const QString &concavity,
int &color, const QByteArray &imagesData = QByteArray());
int size() const { return mSize; }
QString threeDLocation() const { return m3DLocation; }
QString concavity() const { return mConcavity; }
int color() const { return mColor; }
QByteArray imagesData() const { return mImagesData; }
private:
int mSize;
double m3DLocation;
double mConcavity;
int mColor;
QByteArray mImagesData;
};
#endif // ITEMROI_H
I am getting errors on the following parts:
QString threeDLocation() const { return m3DLocation; }
QString concavity() const { return mConcavity; }
Any idea? Thanks

Custom wxDataObject format for XML for copy-paste support

I am trying to implement a custom data object for XML strings, so that if it exists in the clipboard I can parse that accordingly. The code for the XMLDataObject is as follows:
class XMLDataFormat : public wxDataFormat
{
public:
XMLDataFormat() : wxDataFormat(wxT("XMLDataFormat")) {}
};
class XMLDataObject : public wxDataObjectSimple
{
public:
XMLDataObject(const wxString& xmlstring = wxEmptyString) : wxDataObjectSimple(), m_XMLString(xmlstring)
{
SetFormat(XMLDataFormat());
}
size_t GetLength() const { return m_XMLString.Len() + 1; }
wxString GetXML() const { return m_XMLString; }
void SetXML(const wxString& xml) { m_XMLString = xml; }
// Must provide overloads to avoid hiding them (and warnings about it)
size_t GetDataSize() const
{
return sizeof(void*); //or return GetLength()
}
bool GetDataHere(void *buf) const
{
char* c = _strdup(m_XMLString.c_str());
buf = (void*)c;
return true;
}
bool SetData(size_t len, const void* buf)
{
char* c = (char*)buf;
std::string stdString(c, len);
m_XMLString << stdString;
return true;
}
private:
wxString m_XMLString;
};
I send the data to clipboard (when user clicks copy) in the following fashion:
wxDataObjectComposite* dataobj = new wxDataObjectComposite();
dataobj->Add(new XMLDataObject("XML"));
if (wxTheClipboard->Open()) wxTheClipboard->SetData(dataobj);
wxTheClipboard->Close();
To get the data from the clipboard:
if (wxTheClipboard->Open()) {
XMLDataObject xmlObj;
wxTheClipboard->GetData(xmlObj);
if (xmlObj.GetLength() != 0) wxMessageBox(xmlObj.GetXML());
}
wxTheClipboard->Close();
When user clicks paste, I get weird characters instead of the text "XML". I realized that in the functions bool GetDataHere(void *buf) const and bool SetData(size_t len, const void* buf) the address of buf is different. I am not sure but maybe that is how it should be since Clipboard owns the data or behind the scenes wxWidgets is doing something.
By the way, I am using VS 2015 on Windows 10 and using wxWidgets 3.1.0.
Any suggestions is appreciated.
The following code so far has worked correctly:
class XMLDataFormat : public wxDataFormat
{
public:
XMLDataFormat() : wxDataFormat(wxT("XMLDataFormat")) {}
};
class XMLDataObject : public wxDataObjectSimple
{
public:
XMLDataObject(const wxString& xmlstring = wxEmptyString) : wxDataObjectSimple(), m_XMLString(xmlstring)
{
SetFormat(XMLDataFormat());
}
size_t GetLength() const { return m_XMLString.Len() + 1; }
wxString GetXML() const { return m_XMLString; }
void SetXML(const wxString& xml) { m_XMLString = xml; }
size_t GetDataSize() const
{
return GetLength();
}
bool GetDataHere(void *buf) const
{
//char* c = _strdup(m_XMLString.c_str()); not needed as per suggestion
memcpy(buf, m_XMLString.c_str(), m_XMLString.Len()+1);
return true;
}
bool SetData(size_t len, const void* buf)
{
//char* c = new char[len + 1]; not needed as per suggestion
//memcpy(c, buf, len); not needed as per suggestion
m_XMLString = wxString::FromUTF8((const char*)buf); //changed as per suggestion
//delete c;
return true;
}
virtual size_t GetDataSize(const wxDataFormat&) const
{
return GetDataSize();
}
virtual bool GetDataHere(const wxDataFormat&, void *buf) const
{
return GetDataHere(buf);
}
virtual bool SetData(const wxDataFormat&, size_t len, const void *buf)
{
return SetData(len, buf);
}
private:
wxString m_XMLString;
};
Any suggestions as to improve it is again appreciated.

0xC0000005: Access violation writing location 0xCCCCCCCC caused by trying to make safe empty chars

I've been pulling my hair out over a certain error that seems to be plaguing my program. I've attempted to search online for cases similar to mine but I can't seem to find a way to apply the other solutions to this problem. My issue is as follows: When I initially open the program it immediately stops responding and crashes. Debugging led me to find the error in question is "0xC0000005: Access violation writing location 0xCCCCCCCC". It seems to be tied to me assigning two attributes (sku_ and name_ ) as '\0'. If I change these values to anything else such as "" or even "\0" the program runs in visual studio, but will fail to compile elsewhere. Could someone help me understand where I am going wrong?
Product.h
#ifndef SICT_Product_H__
#define SICT_Product_H__
#include "general.h"
#include "Streamable.h"
#include <cstring>
namespace sict {
class Product : public Streamable {
char sku_ [MAX_SKU_LEN + 1];
char* name_;
double price_;
bool taxed_;
int quantity_;
int qtyNeeded_;
public:
//Constructors
Product();
Product(const char* sku, const char* name1, bool taxed = true, double price = 0, int qtyNeeded =0);
Product(Product& g);
~Product();
//Putter Functions
void sku(const char* sku) { strcpy(sku_,sku); };
void price(double price) {price_ = price;};
void name(const char* name);
void taxed(bool taxed) { taxed_ = taxed; };
void quantity(int quantity) { quantity_ = quantity; };
void qtyNeeded(int qtyNeeded) { qtyNeeded_ = qtyNeeded; };
//Getter functions
const char* sku() const { return sku_; };
double price() const { return price_; };
const char* name() const { return name_; };
bool taxed() const { return taxed_; };
int quantity() const { return quantity_; };
int qtyNeeded() const { return qtyNeeded_; };
double cost() const;
bool isEmpty() const;
Product& operator=(const Product& );
bool operator==(const char* );
int operator+=(int );
int operator-=(int );
};
double operator+=(double& , const Product& );
std::ostream& operator<<(std::ostream& os, const Product& );
std::istream& operator>>(std::istream& is, Product& );
}
#endif
Product.cpp
#include <iostream>
#include <cstring>
#include "Product.h"
namespace sict {
Product::Product() {
sku_[0] = '\0';
name_[0] = '\0';
price_ = 0;
quantity_ = 0;
qtyNeeded_ = 0;
}
Product::Product(const char* sku, const char* name1, bool taxed1, double price1, int qtyNeeded1) {
strncpy(sku_, sku, MAX_SKU_LEN);
name(name1);
quantity_ = 0;
taxed(taxed1);
price(price1);
qtyNeeded(qtyNeeded1);
}
double Product::cost() const {
if (taxed_ == true) {
return (price_ * TAX) + price_;
}
else
return price_;
}
bool Product::isEmpty() const{
if (sku_ == nullptr && name_ == nullptr && quantity_ == 0 && price_ == 0 && qtyNeeded_ == 0) {
return true;
}
else
return false;
}
Product::Product(Product& ex) {
sku(ex.sku_);
price(ex.price_);
name(ex.name_);
taxed(ex.taxed_);
quantity(ex.quantity_);
qtyNeeded(ex.qtyNeeded_);
}
Product& Product::operator=(const Product& g) {
sku(g.sku_);
price(g.price_);
name(g.name_);
taxed(g.taxed_);
quantity(g.quantity_);
qtyNeeded(g.qtyNeeded_);
return *this;
}
Product::~Product() {
delete [] name_;
}
void Product::name(const char* name) {
name_ = new char [strlen(name) + 1];
strcpy(name_, name);
}
bool Product::operator==(const char* right) {
if (sku_ == right) {
return true;
}
else
return false;
}
int Product::operator+=(int g) {
quantity_ = quantity_ + g;
return quantity_;
}
int Product::operator-=(int g) {
quantity_ = quantity_ - g;
return quantity_;
}
double operator+=(double& p, const Product& right) {
p = p + (right.cost() * right.quantity());
return p;
}
std::ostream& operator<<(std::ostream& os, const Product& g) {
return g.write(os, true);
}
std::istream& operator>>(std::istream& is, Product& g) {
return g.read(is);
}
}
The General.h file referenced in the header is just a list of constant values such as the "TAX" and "MAX_SKU_LEN" values.
The Streamable header contains pure virtual functions. I will list it here in case it is needed.
Streamable.h
#ifndef SICT__Streamable_H_
#define SICT__Streamable_H_
#include <iostream>
#include <fstream>
#include "Product.h"
namespace sict {
class Streamable {
public:
virtual std::fstream& store(std::fstream& file, bool addNewLine = true)const = 0;
virtual std::fstream& load(std::fstream& file) = 0;
virtual std::ostream& write(std::ostream& os, bool linear)const = 0;
virtual std::istream& read(std::istream& is) = 0;
};
}
#endif
Thank you very much in advance.
Product::Product() {
sku_[0] = '\0';
name_[0] = '\0'; // <---- writing via unitialized pointer
price_ = 0;
quantity_ = 0;
qtyNeeded_ = 0;
}
There's one possible source of your problems. You have defined a char pointer (a dynamic array or a C-string, that is) name_ in your class but you never allocate any memory for it in your constructor, before attempting to record a value via the pointer. Naturally, you get a write access violation.
Before assigning the value to char at index [0] you need to first allocate space for at least one element in your string, e.g. by doing name_ = new char [1]. Alternatively, you may choose to initialize the pointer itself to NULL (or nullptr) and use that to indicate that name_ has not yet been set.

Comparing Items in QList qt5.3

I am trying to compare the items in a QList.
Here is the old way to do it using QPtrCollection but this cannot be used in versions after qt3 (as far as I'm aware).
class gnyComponentList:public QList<gnyComponent>
{
protected:
virtual int compareItems ( QPtrCollection::Item item1, QPtrCollection::Item item2 )
{ return (((gnyComponent *)item1)->getID()).compare(((gnyComponent *)item2)->getID());}
};
I can't figure out what a good way of doing this in Qt5.3 might be?
You can use the std::equal algorithm on QList objects, as in:
#include <QList>
#include <QString>
#include <algorithm> // for std::equal
struct Person
{
QString firstName;
QString lastName;
};
int main()
{
QList<Person> personsA, personsB;
// Populate personsA and personsB
bool equal = std::equal( personsA.begin(), personsA.end(),
personsB.begin(),
[]( const Person &a, const Person & b ) {
return a.firstName == b.firstName;
} );
}
This is a simple one, which compares every item without sorting.
Here is the code.
bool TeachTab::isTwoStringListEqual(const QStringList &dst,
const QStringList &src) {
if (dst.size() != src.size())
return false;
for (int i = 0; i < dst.size(); ++i) {
if (dst.value(i) != src.value(i)) {
return false;
}
}
return true;
}

Fix QString size (length)

For some reason I need to use string with fixed size. Now I'm looking on a QString class.
But there I have some questions with making QString object having constant size.
For example, I want to have string with size 10, it means, that if I would try to write some string with more than 100 chars in it, it would cut all the characters after 100 one.
I found constructor for QString in Qt docs, but I'm not sure if it would work as I told
QString( int size , QChar ch)
What can you suggest in such situation?
You can have a wrapper class that has a string, but is not a string, yet it can be used wherever a QString could be used. It can also be used with all QString's methods and operators, as long as you treat it like it were a pointer.
#include <QString>
class FixedWidthString {
mutable QString m_string;
//! Ignored if negative.
int m_maxLength;
inline const QString& data() const {
if (m_maxLength >= 0 && m_string.length() > m_maxLength)
m_string.truncate(m_maxLength);
return m_string;
}
inline QString& data() {
if (m_maxLength >= 0 && m_string.length() > m_maxLength)
m_string.truncate(m_maxLength);
return m_string;
}
public:
explicit FixedWidthString(int maxLength = -1) : m_maxLength(maxLength) {}
explicit FixedWidthString(const QString & str, int maxLength = -1) : m_string(str), m_maxLength(maxLength) {}
operator const QString&() const { return data(); }
operator QString&() { return data(); }
QString* operator->() { return &data(); }
const QString* operator->() const { return &data(); }
QString& operator*() { return data(); }
const QString& operator*() const { return data(); }
FixedWidthString & operator=(const FixedWidthString& other) {
m_string = *other;
return *this;
}
};
int main() {
FixedWidthString fs(3);
FixedWidthString fs2(2);
*fs = "FooBarBaz";
Q_ASSERT(*fs == "Foo");
fs->truncate(2);
Q_ASSERT(*fs == "Fo");
fs->append("Roo");
Q_ASSERT(*fs == "FoR");
fs->truncate(1);
*fs += "abc";
Q_ASSERT(*fs == "Fab");
fs2 = fs;
Q_ASSERT(*fs2 == "Fa");
}