C++ Calling a getter method when it is not ready - c++

I'm working on a project and it works but it is really messy so I am trying to clean it up by moving things around.
Here is a short version of the class containing the getter method
Link::Link
{
jsonUrl = QUrl("www.example.json");
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(downloadFinished(QNetworkReply*)));
QNetworkRequest request(jsonUrl);
nam->get(request)
}
void Link::downloadFinished(QNetworkReply *reply)
{
jsonArray = reply->readAll();
jsonStuff();
}
void Link::jsonStuff()
{
//does a bunch of json stuff then gets a string
string = map["url"].toString();
}
QString Link::getString()
{
return string;
}
Here is a short version of the class that calls the getter in the constructor
Header
class Commands
{
private:
Link link;
}
Source inside the constructor
Commands::Commands()
{
addCommand("!test", link.getString());
}
The problem is when I try to do it like this, I think the Commands constructor runs first and the string from the Link class is not ready yet so the string that comes out of link.getString() is empty. Is there a way to wait until the Link class finishes doing it's stuff and fills up the string before calling link.getString() inside the constructor of Commands? Not sure if this matters but most of my code is written in Qt
I hope you guys can understand what I'm trying to ask. My terminology is really poor.
Edit: Added more to my Link class

When the constructor of Commands (in this case Commands()) is called firstly it creates all variables(they are unintialized) in Commands class. That being said link is created via Link(). What you might want to do is to use jsonStuff() in the Link() constructor (it creates all member variables as well as), NOTE THAT it creates variables in this case it creates string with base costructor - it creates empty string.) Try following to fill the string:
Link() {
jsonStuff(); // string will be set
}
Or you can initialize it via initialization section:
Link() : string("Text") { }
Also you might want to return reference to string from getString() function. Reference means it doesn't create additional copy and it returns string which is stored in Link, so you can change string in a function where getString() is called. Also if it is read only you should use const reference.

Is there a way to wait until the Link class finishes doing it's stuff and fills up the string before calling link.getString() inside the constructor of Commands?
Certainly. The Link class must be a QObject that emits a signal when it has changed its properties - presumably based on the replies it got to its network request.
class Link : public QObject {
Q_OBJECT
Q_PROPERTY(QString string READ string WRITE setString NOTIFY stringChanged)
QString m_string;
public:
void jsonStuff() {
...
connect(reply, &QNetworkReply::finished, this, [this]{
...
setString(map["url"].toString());
});
}
void setString(const QString &s) {
if (m_string == s) return;
m_string = s;
emit stringChanged(m_string);
}
QString string() const { return m_string; }
Q_SIGNAL void stringChanged(const QString &);
};
You can then add the command when the link is ready:
Commands::Commands()
{
connect(&link, &Link::stringChanged, this, [this](const QString &string){
if (!string.isEmpty()) addCommand("!test", string);
});
}

Related

How to initialize QXmlStreamWriter with QString as member variable?

I have implemented my own xml writer to generate xml as QString.
i have create a class "MyXmlWriter" with private member variable as QXmlStreamWriter and try to initialize it in the public method writeToString()
in declaration header file:
class MyXmlWriter {
public:
MyXmlWriter();
~MyXmlWriter();
QString writeToString();
private:
QXmlStreamWriter writer;
void writePart();
}
in cpp file:
void MyXmlWriter::writePart() {
// i want to use the QXmlStreamWriter instance hier
}
QString MyXmlWriter::writeToString(){
QString result;
writer(&result); // at this became the error: no match for call to '(QXmlStreamWriter) (QString*)'
xmlWriter.setAutoFormatting(true);
// private method called
writePart();
return result;
}
this error appear on build:
error: no match for call to (QXmlStreamWriter) (QString) writer(&result); *
If the QXmlStreamWriter write is declared in the local method writeToString() then i cant access this writer in private method writePart()
i want to use the member variable "writer" in other methods that's why a local declaration isn't an option for me.
You have to assign a new object to your variable writer, like this:
QString MyXmlWriter::writeToString() {
QString result;
writer = QXmlStreamWriter(&result); // will not compile
return result;
}
This code is dangerous. result is destroyed at the end of writeToString(), so writer then contains invalid data and you cannot use it anymore.
Additionally, QXmlStreamWriter cannot be copied, so this would probably not compile at all. It's better to just pass the QXmlStreamWriter to your methods, like this:
class MyXmlWriter {
public:
MyXmlWriter();
~MyXmlWriter();
QString writeToString();
private:
void writePart(QXmlStreamWriter &writer);
}
and
QString MyXmlWriter::writeToString() {
QString result;
QXmlStreamWriter writer(&result);
writePart(writer);
writePart(writer);
return result;
}

Passing class pointer to a function

I want to use different WText instances in another function, but as I want to have just one control function, I'd like to pass them in there.
The code with current setup compiles but fails due to some memory fault which I don't understand.
class mode : public WApplication
{
//..
private:
//..
void someFunc();
void control(WText* texty);
WText* text;
WText* text2;
WText* text3;
//...etc
};
void mode::someFunc(){
control(text); //how to pass it?
//might pass text2 or text3 as well
}
void mode::control(WText* texty){
texty->setText("blabla");
//..
}
text member is a pointer to the object WText,
The first thing you need to do is a create a new WText object:
void mode::someFunc() {
text = new WText();
control(text);
}
please remember about destroy text object after use.

C++ Setting member object which has const member

I am using OIS for handling my input with Ogre and currently, on KeyPress/Release a Message object like the following will be constructed and distributed among subscribers.
class Message
{
public:
Message();
~Message();
inline void SetKeyEvent(const OIS::KeyEvent& keyEvent) { _keyEvent = keyEvent; }
const OIS::KeyEvent& GetKeyEvent() const { return _keyEvent; }
private:
OIS::KeyEvent _keyEvent;
};
Since this object will be constructed/destroyed whenever input is received via keyboard, I am trying to store a pre-constructed Message object and then simply update the _keyEvent field with the new data, before distributing.
The problem is that the OIS::KeyEvent object has a const member which is preventing me from using the assignment operator. The SetKeyEvent method gives me the following syntax error:
function "OIS::KeyEvent::operator=(const OIS::KeyEvent &)" (declared implicitly) cannot be referenced -- it is a deleted function
I was wondering what the best way to achieve this functionality would be?
Thanks in advance
EDIT: Just to clarify, I already use initializer lists when possible. My intention is to have the Message object pre-constructed and then update the _keyEvent field with the new event data from the KeyPress event which OIS fires, using the SetKeyEvent method. I would like to know if this is possible and if so, what the best way to do it would be.
The copy operator is deleted, so you must work with pointers.
class Message
{
public:
Message();
~Message();
inline void SetKeyEvent(OIS::KeyEvent* keyEvent) { _keyEvent = keyEvent; }
const OIS::KeyEvent& GetKeyEvent() const { return _keyEvent; }
private:
OIS::KeyEvent* _keyEvent;
};
And now it's better to check if the argument in the setter isn't nullptr.
inline void SetKeyEvent(OIS::KeyEvent* keyEvent)
{
assert(keyEvent != nullptr);
_keyEvent = keyEvent;
}
assert() needs #include <assert.h>
EDIT:
Sorry, forgot the getter method. You must use pointers, too.
const OIS::KeyEvent* keyEvent = &Message.GetKeyEvent();
Where Message is your class instance.
It is possible by using placement new and an explicit destructor call, things you normally should never do:
inline void SetKeyEvent(const OIS::KeyEvent& keyEvent)
{
_keyEvent.~KeyEvent();
new (&_keyEvent) OIS::KeyEvent(keyEvent);
}
This is bad ugly horrible code, use at your own risk.

Error passing custom Object from QtScript to C++

I have written a custom class which is available in QtScript through a Prototype. Also another global class is available which should be used to print the custom class generated in QtScript.
This is my custom class (very simple ;) ):
class Message
{
public:
int source;
int target;
};
This is the prototype I am using:
class MessagePrototype : public QObject, public QScriptable
{
Q_OBJECT
Q_PROPERTY(int source READ getSource WRITE setSource)
Q_PROPERTY(int target READ getTarget WRITE setTarget)
public:
void setSource(const int source);
int getSource() const;
void setTarget(const int target);
int getTarget() const;
};
The setter / getter are only changing / printing the corresponding Message object through a qscriptvalue_cast(QScriptable::thisObject());
Now my script looks like this:
var test = new Message;
test.source = 5;
print(test.source);
GlobalObject.sendMessage(test);
So, the script compiles fine and the print() command does what it should, it prints 5. But the problem is the sendMessage function of my GlobalObject:
void MessageAnalysis::sendMessage(Message msg)
{
qDebug() << "[Message]" << msg.source << msg.target;
}
This piece of code always prints: "[Message] 0 0".
MessageAnalysis is registered as "GlobalObject" for QtScript. Also I have registered Message and Message* as Metatypes and the constructor, prototype and everything else. This seems to work.
Does anyone knows why the values have been changed in QtScript but are not accessible from my C++ function? Or what I am doing wrong?
Ok. After several attempts I fixed it.
I changed the sendMessage function to accept a QScriptValue instead of a Message as parameter. Now I can get the properties out of it without problems.
Seems to work fine now :)

Segfaults with singletons

// Non singleton
class MyLogManager
{
void write(message) {Ogre::LogManager::getSingletonPtr()->logMessage(message);}
}
class Utils : public singleton<Utils>
{
MyLogManager *handle;
MyLogManager& getHandle { return *handle; }
};
namespace someNamespace
{
MyLogManager &Log() { return Utils::get_mutable_instance().getHandle(); }
}
int main()
{
someNamespace::Log().write("Starting game initializating...");
}
In this code I'm using boost's singleton (from serialization) and calling Ogre's log manager (it's singleton-type too).
The program fails at any trying to do something with Ogre::LogManager::getSingletonPtr() object with code
User program stopped by signal (SIGSEGV)
I checked that getSingletonPtr() returns address 0x000
But using code Utils::get_mutable_instance().getHandle().write("foo") works good in another part of program. What's wrong could be there with calling singletons?
Real version of Utils class:
class Utils : public singleton<Utils>
{
protected:
ConfigManager *configHandlePtr;
LogManager *logHandlePtr;
public:
Utils()
{
configHandlePtr = new ConfigManager();
string engineLog = configHandle().getValue<string>("engine.logFilename", "Engine.log");
logHandlePtr = new LogManager(engineLog);
}
~Utils()
{
delete configHandlePtr;
delete logHandlePtr;
}
ConfigManager &configHandle() const { return *configHandlePtr; }
LogManager &logHandle() const { return *logHandlePtr; }
};
And here is the real code of LogManager class:
class LogManager
{
protected:
string mDefaultPath;
public:
LogManager(const string &logPath = "Engine.log") :
mDefaultPath(logPath) { }
void write(const string &message, const string logFile = "")
{
string workPath = mDefaultPath;
Ogre::LogManager *logHandle = Ogre::LogManager::getSingletonPtr(); // [logHandle=0x000]
Ogre::Log *log2Handle = logHandle->getLog(workPath); // [SEGFAULT]
log2Handle->logMessage(message);
Ogre::LogManager::getSingletonPtr()->logMessage(message);
}
};
UPDATE:
I have a static library (there is my engine code) and the main own programm which links static this library. When I call my config handle (which doesn't use Ogre) everything is okay! There is also resourceManager, it uses Ogre too. And it fails like logManager. Both this managers uses Ogre's singleton. Maybe it's impossible to call it from another library?
It feels like you have typical "static initialization order fiasco" - your Utils instance created before one (or both) of other singletons.
Try change Utils::configHandle() to something like this:
ConfigManager &configHandle() const {
static std::auto_ptr<ConfigManager> configHandlePtr(0);
if (!configHandlePtr.get()) {
configHandlePtr.reset(new ConfigManager());
// init configHandlePtr like you want
}
return *configHandlePtr;
}
I don't know Boost's singleton, but I notice some strange things in your 'Utils' class.
First of all, getHandle returns a reference to handle, but handle is a local variable that goes out of scope if you leave the method, so the reference to it will also be invalid.
Second, you didn't initialize handle in the getHandle method.
Are you sure your Ogre LogManager is correctly initialized?
Or maybe with your libraries you have one instance of the singleton in each library and only the one in your main program is correctly initialized?
In this case you have to declare the singletons in your libraries as "extern" but I'm not sure it applies to statically linked libraries.