I don't have much experience with Qt but somehow I think this is acting strange.
Compiled with VS2005:
class Entry
{
public:
Entry(const QString& aName, bool checked) :
name(aName), isChecked(checked)
{
// empty
};
Entry(const Entry& entry) :
name(entry.name), isChecked(entry.isChecked)
{
// empty
};
Entry& operator=(const Entry& entry)
{
name = entry.name;
isChecked = entry.isChecked;
return *this;
}
QString name;
bool isChecked;
};
typedef QList<conduit::Entry> EntryVector;
When using EntryVector in the following lines, the entry in QList becomes a bad pointer:
void EntryWidget::setEntries(QStringList& names)
{
QStringList::iterator member;
EntryVector list;
for (member = names.begin(); member != names.end(); ++member)
{
Entry entry(*member, false);
list.append(entry);
}
m_model.setEntryData(list);
}
Somehow, entry.name in the list will become a bad pointer. My understanding is that QList should be able to support any data in its template, but for some reason that I yet do not understand this does not work. Everything works just fine if I use a STL Vector.
Any ideas? Thanks
I had this same problem, and came looking for anwsers.
I though my code was misbehaving, when it's not.
VS2005 debugger doesn't show you the things in QList correctly.
And as davmac suggested, when you print the stuff out, it works fine.
And davmac, please don't point out that he might have a memory corruption when the guy gives you a piece of code to try. If you can't try it with the same setup, that's another thing.
"entry.name" isn't a pointer - it's declared as a QString, here:
public: QString name;
So, what do you mean by "entry.name will become a bad pointer"?
Most likely, some other part of your program is causing a memory corruption.
I assume, that QStringList makes a depth-copy of the Strings in its copy-ctor.
And we know QList makes no depth-copy. see QList and implicit sharing
So, at the call of
void EntryWidget::setEntries(QStringList& names) {...}
Strings in names are copied.
But when you set the new Entry-List to the model,
m_model.setEntryData(list);
the list is not copied into mmodel.xy.
Now you can access mmodel.xy, but the strings you assign in setEntries(..) are already deleted.
They lost their scope, when you leave the setEntries(..) method.
Note:
QString is a reference pointer to a String. This is called "implicit sharing" .
And all containers in Qt have the concept of lazy-evaluation.
(Probably except the QStringList, which makes a depth-copy. This is perhaps a little bug in Qt. I can it only say 100% if I see the .cpp)
qt-project.org/doc/qt-5/qstringlist.html#QStringList-3
Related
I'm working on an assignment that uses OMNeT++, Veins/Sumo. Although my question is not completely related to it, it might add some context.
I'm familiar with programming, but having a little bit of trouble wrapping my head around the whole
The idea is that there is a network of cars, and all these cars are talking to eachother using messages. A message inlcudes the vehicle name, but also information about the current position/mobility of the car. This is where TraCIMobilitycomes in.
Ideally I would like to have all this information stored in the original class in the message, but I am running into some issues.
pointer/memory address idea when working with classes.
class InterVehicleMessage : public ::veins::DemoSafetyMessage
{
protected:
::omnetpp::opp_string vehicleName;
veins::TraCIMobility vehicle_mobility; <--- important
private:
void copy(const InterVehicleMessage& other);
protected:
bool operator==(const InterVehicleMessage&);
public:
//stuff
virtual veins::TraCIMobility& getMobility(); <--- important
virtual const veins::TraCIMobility& getMobility() const {return const_cast<InterVehicleMessage*>(this)->getMobility();} <--- important
virtual void setMobility(const veins::TraCIMobility& vehicle_mobility); <--- important
};
This all looks fine and dandy, I assume it functions as intended aswell.
But then when I try to make define the setMobility class I run into some problems.
void InterVehicleMessage::SetMobility(const veins::TraCIMobility& vehicle_mobility)
{
this->vehicle_mobility = vehicle_mobility;
}
This results in the error:
InterVehicleMessage_m.cc:240:28: error: object of type 'veins::TraCIMobility' cannot be assigned because its copy assignment operator is implicitly deleted
I'm not familiar with C++ enough to really know what this means. Is there anyone who could hint me into the right direction?
pastebin to TraCIMobility.h: https://pastebin.com/pGZEepxX
I've decided to save the information necesarry from TraCIMobility in individual variables.
So:
double speed;
veins::Coord position;
veins::Heading direction;
veins::Coord nextPositions[7];
Instead of:
veins::TraCIMobility vehicle_mobility;
As #PaulSanders stated in the comment, this class is not supposed to be copied.
Thanks everyone for their time and effort. Have a nice day.
I'm a newbie in C++, trying to study C++. I have a block of code in Java like this:
public List<String> getDiagnosticTroubleCode() {
if (diagnosticTroubleCode == null) {
diagnosticTroubleCode = new ArrayList<String>();
}
return this.diagnosticTroubleCode;
}
How can I compare the disgnosticTroubleCode with null value? and set it as a new List. I already override the std::list to make it use like List in Java. And then I want to return the diagnosticTroubleCode field within the object this. I hope that you guys can help me with this. Trying to study about this pointer and null.
Here is my header in C++ :
class RUNTIME_EXPORTS DiagnosticTroubleCode {
protected:
List diagnosticTroubleCode;
public:
List getDiagnosticTroubleCode();
};
Your code appears to desire only instantiating diagnosticTroubleCode on first use. Frankly, I find that somewhat odd, since an instance of an otherwise-empty std::list<std::string> would be rather benign. Regardless, this is one way to do that.
class DiagnosticTroubleCode
{
protected:
std::unique_ptr<std::list<std::string>> diagnosticTroubleCode;
public:
std::list<std::string>& getDiagnosticTroubleCode()
{
if (!diagnosticTroubleCode)
diagnosticTroubleCode = std::make_unique<std::list<std::string>>();
return *diagnosticTroubleCode;
}
};
Note that the member getDiagnosticTroubleCode will return a reference to the new (or existing) instantiated list. If you decide to forego latent instantiation (I recommend doing so), the code becomes considerably simpler:
class DiagnosticTroubleCode
{
protected:
std::list<std::string> diagnosticTroubleCode;
public:
std::list<std::string>& getDiagnosticTroubleCode()
{
return diagnosticTroubleCode;
}
};
If the latter is possible (and frankly, I cannot see how it isn't), pursue that first. IN both cases above the member is returned by reference, not value or address. This would most-closely resemble what you're probably familiar with.
Best of luck.
I remember in Java everything are pointers. So in Java diagnosticTroubleCode == null is essentially comparing diagnosticTroubleCode with a null pointer. In C++ we do not have null, we have NULL or nullptr. In C++ an object cannot really be null because it is not. An object takes up a block of memory when it gets constructed, so it can never be null. So try to familiarize yourself with pointers and use that in your advantage.
On the matter of this. If you want to return a member variable, you don't really need to write return this.variable, you can simply return the variable by writing return variable.
The difference here is that in Java all complex structure declarations are really declarations of references to such structures. In C++, that's the equivalent of saying List& foo or List* foo. C/C++ declarations are true instances, which is one of the reasons why there can be a bit of complexity with memory management, but it comes with the benefit of information integrity: For example, when you pass a Java List<String> as an argument of a method and change the contents of that argument, it's changed in the calling scope. C/C++, on the other hand, will copy the argument regardless of object complexity, and when the function/method returns, the one passed as an argument is otherwise preserved.
Your C++ class example should look something like this:
#include <list>
#include <string>
using namespace std;
class RUNTIME_EXPORTS DiagnosticTroubleCode {
protected:
list<string>* diagnosticTroubleCode{nullptr};
public:
list<string>* getDiagnosticTroubleCode();
};
list<string>* DiagnosticTroubleCode::getDiagnosticTroubleCode(){
if (diagnosticTroubleCode == nullptr) {
diagnosticTroubleCode = new List<string>();
}
return diagnosticTroubleCode;
}
There are better implementations that don't require returning a pointer or reference, but they impose additional design requirements (such as what the adding a trouble-code mechanism should be).
You could use something like this
#include <iostream>
using namespace std;
Function
class DiagnosticTroubleCode
{
protected:
std::unique_ptr<std::list<std::string>> diagnosticTroubleCode;
public:
std::list<std::string>& getDiagnosticTroubleCode()
{
if (!diagnosticTroubleCode)
diagnosticTroubleCode = std::make_unique<std::list<std::string>>();
return *diagnosticTroubleCode;
}
};
My .cpp file :
shared_ptr<List> DiagnosticTroubleCodes::getDiagnosticTroubleCodes()
{
if (this->diagnosticTroubleCodes == nullptr) {
this->diagnosticTroubleCodes = make_shared<List>();
}
return diagnosticTroubleCodes;
}
And My header file:
class RUNTIME_EXPORTS DiagnosticTroubleCodes {
protected:
shared_ptr<List> diagnosticTroubleCodes;
public:
shared_ptr<List> getDiagnosticTroubleCodes();
};
I come up with this solution.
I'm writing a program for my friends during my summer time and I occurred really strange problem.
I'm assigning a QVector< T > to other QVector< T > with operator= in my homemade template class and then trying to check whethere this 2nd QVector< T > have any elements. First, I'm checking it's size and it's good, but when I use operator[] and function GetName() which is a member of class T.
Here's some code:
template <template T> class Turniej {
private:
QVector<T>* list_;
QVector<Stol<T> > stoly_;
int round_;
int max_rounds_;
Turniej() {round_=1;}
public:
static Turniej& GetTurniej() {
static Turniej turniej;
return turniej; }
void SetList(QVector<T> *list) {list_=list; }
QVector<T>& GetList() {return *list_;}
//Some other irrelevant methods
};
Then I invoke SetList() function with reference to QVector filled with 2 objects of Gracz class
Turniej<Gracz>::GetTurniej().SetList(&list)
And when I'm finally trying to get to the list_ object in Turniej class by code below, I get this error:
ASSERT failure in QVector::operator[]: "index out of range", file .../QtCore/qvector.h, line 356
qDebug()<<Turniej<Gracz>::GetTurniej().GetList()[0].GetName();
Where GetName() returns some QString and for certain that method exists in Gracz class.
I would really appreciate any help, because I'm stuck with it for 2 days and have completely no idea what's going on. What is strange, I was trying to google that error but I haven't found any topic with error in that particular line of qvector.h.
I'm using Qt 5.0.2 with Qt Creator
Thanks for any help!
when you call SetList, you are transferring the ownership of the list, are you shure you are not deleting it (or it is not getting deleted automatically) afterwards?
Change list_=list; to list_ = new QVector(list). Maybe your vector is modified somewhere outside of your class? You're just keeping reference to vector given to your method, it seems like copying is what you want.
updated
I see your class is a singleton. Always remember to think twice before making a class a singleton - it's not a thing you want to have in your code, and it should be avoided when possible.
I am trying to replace a class method which returns const std::string & with const boost::interprocess::basic_string &. The main challenge I am facing is the incompatibility between the two classes despite their implementation similarity. For more clear explanation I will put that into code
class A
{ std::string m_str;
const std::string & StrVal() { return m_str; }
}
Now this class has to look like this:
typedef boost::interprocess::allocator<char,boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocatorChar;
typedef boost::interprocess::basic_string<char, std::char_traits<char>,ShmemAllocatorChar> ShMemString;
class A
{
ShMemString m_str;
const ShMemString & StrVal() { return m_str; }
}
The problem is that we have a huge code base depending on this:
A a;
const std::string & str = a.StrVal();
// Many string specific operations go here, comparing str with other std::strings for instance
Even If I go over all the code replacing the expected results with const ShMemString &, it will be an even harder work to also fix the uses that follow. I was surprised to find out that the boost's string does not include any comparison/construction methods from std::string.
Any ideas on how to approach this?
Even if boost::interprocess::basic_string<> did have a conversion to std::basic_string<>, it would be completely useless for your purposes -- after the conversion, the interprocess string would be destroyed, and its allocator is the important one (i.e., the one holding the data in shared memory, which I assume is your motivation for switching basic_string<> implementations in the first place).
So, in the end, you have no choice but to go over all the code replacing the expected results with ShMemString const& (or auto const& if your compiler is recent enough to support it).
To make this less painful in the future, typedef judiciously:
struct A
{
typedef ShMemString StrValType;
StrValType const& StrVal() { return m_str; }
private:
StrValType m_str;
};
// ...
A a;
A::StrValType const& str = a.StrVal();
This way, only the typedef inside of A needs to change and all code relying on it will automatically use the correct type.
The problem is that we have a huge code base depending on this:
Why does A::StrVal in the second one return an interprocess::basic_string? It is an implementation detail of the class A that it uses interprocess::basic_string internally. The actual string class it's interface uses does not have to be the same. This is simply poor refactoring.
A::StrVal should return a std::string, just like always (well, not a const& of course, but user code won't need to change because of that). And therefore, A::StrVal will need to do the conversion between the two string types. That's how proper refactoring is done: you change the implementation, but the interface stays the same.
Yes, this means you're going to have to copy the string data. Live with it.
I have a CognitiveEntity class, defined this way:
class CognitiveEntity : public Object
{
public:
CognitiveEntity (FuzzyCognitiveMap fcm, SystemState s);
~CognitiveEntity ();
template <typename T> void RegisterChange (std::string context, T value);
bool operator!= (const CognitiveEntity& rhs) const;
private:
FuzzyCognitiveMap m_fuzzyCognitiveMap;
SystemState m_systemState;
std::vector <SystemState> RunFuzzyCognitiveMap ();
};
As shown, a CognitiveEntity has a SystemState object, which in turn has a vector of Concept objects (only the most relevant lines are shown):
class SystemState
{
public:
SystemState ();
~SystemState ();
void AddConcept (Concept c) { m_L.push_back(c); }
std::vector <Concept> m_L;
};
Inside the CognitiveEntity::RegisterChange, I mark a Concept as a potential cause (by calling Concept::IsPotentialCause (bool) which merely sets a private member with the value passed):
template <typename T>
void
CognitiveEntity::RegisterChange (std::string context, T value)
{
std::string name = context.substr(context.find_last_of ("/") +1);
int pos = m_systemState.FindConcept(name);
if (pos > -1)
{
int intValue = value ? 1 : 0;
m_systemState.m_L[pos].SetConceptValue (intValue, false);
if (m_systemState.m_L[pos].CheckVariation ())
{
m_systemState.m_L[pos].IsPotentialCause (true); // Mark this concept as a potential cause
for (int cause = 0; cause < m_systemState.GetSize (); cause++)
{
if ( (cause != pos) && (m_systemState.m_L[cause].MayBeCause ()))
{
m_fuzzyCognitiveMap.UpdateFuzzyCognitiveMapEntry (cause, pos, m_systemState);
m_systemState.m_L[cause].IsPotentialCause (false);
}
}
}
}
}
What happens is that as soon as RegisterChange is called another time, the Concept that was marked as potential cause, is marked no more.
I tried running gdb and I am sure that that member is not set elsewhere.
I'm not sure if this little information is enough for you to give me some hints about such a behavior (I didn't want to flood the post with the code of both SystemState and Concept classes).
Regards,
Jir
If this was a multi-threaded system, I'd say it sounds like a classic case of shared, mutable state that wasn't properly synchronized.
If you don't have a multi-threaded situation, I'd say set a watch on that variable and see what changes it.
Turns out the problem lied in how the code was called from within the network simulator (the code was meant to be used in the "ns-3" network simulator).
So, the problem wasn't even in the code I posted, and yet you managed to help me find the solution: thanks to the suggestions you gave me, I prepared a standalone version of the code and I watched the variable.
The problem was how I was passing the object.
Specifically, instead of passing around the object by reference (as I thought I was doing) I should have used smart pointers.
Thank you all for the great insights!
(and sorry for the mess... next time I'll be more accurate!)