I have a QHash<QString, myClass*> objects and in order to insert I did the following:
myClass *value = objects.value(key);
if(!value) {
value = new myClass;
objects.insert(key, value);
}
Is this right approach?
Your solution is one of several possible correct approaches.
I usually do it like this as I find it a bit more readable
if( !objects.contains( key ) )
{
objects.insert( key, new MyClass );
}
MyClass* value = objects.value( key);
As already suggested by Marek R, you can use smart pointers for easier memory management:
QHash< QString, QSharedPointer< MyClass > > objects;
// ...
QSharedPointer< MyClass > value = objects.value( key );
Since C++11, I prefer using std::shared_ptr.
This allows you to not care about delete calls; just make sure you always use QSharedPointer< MyClass > instead of MyClass* everywhere. Also, you mustn't use shared pointers for QObject subclasses which have a parent, as the parent object will store a regular pointer for it.
Related
My struct class:
public struct PinAndRadius
{
public string pinID { get; set; }
public string radiusID { get; set; }
public string getPinID()
{
return pinID;
}
public string getRadiusID()
{
return radiusID;
}
}
the method with a problem:
void mapArea_VE_PinDragged(double latitude, double longitude, object id)
{
foreach (var pin in pinRadiusCollection)
{
string ID = id.ToString();
//string newID = ID.Substring(0, 18);
if (!pin.Key.pinID.Equals(ID))
{
continue;
}
else if (pin.Key.pinID.Equals(ID))
{
var newLoc = createNewSearchLocation(latitude, longitude);
mapArea.VE_DeleteRadius(pin.Key.radiusID);
drawPoly(newLoc, pin.Value.xar_Radius);
pin.Key.radiusID = pollyID;
break;
}
}
}
The problem is that when I try to set pin.key.radiusID to pollyID, I get an error saying
Cannot modify the return value of 'System.Collections.Generic.KeyValuePair.Key' because it is not a variable...
Any ideas?
Structure in .net is value-type. This mean you can't get reference to PinAndRadius using pin.Key. You will get copy of pin.Key of type PinAndRadius. Then you haven't access to this copy and compiler tell you about this. In C++ terms it not l-value.
If you create struct always try make it immutable. Mutable structs are evil.
Simplest way to solve this problem is to make PinAndRadius as class.
By the looks of it, your pinRadiusCollection is a generic dictionary keyed by PinAndRadius; the error you're getting is letting you know you can't modify that object because it's being used as the key in your dictionary.
If your pins are supposed to be mutable, you should probably revisit how you're storing them.
Collections in .net are not set up to allow convenient modification of struct-type items contained therein. Despite this, mutable structs still offer cleaner semantics than any other kind of data type. To edit a struct held in a collection, simply copy it to a variable, edit that variable, and store it back:
var temp = myList[someIndex];
temp.SomeVield = whatEver;
myList[someIndex] = temp;
Note that it's generally better to have mutable structs expose their contents as fields than as properties. Some people may say mutable structs are evil because their semantics differ from classes, but that's like saying screwdrivers are evil because they make lousy hammers. Exposed-field structs don't work like class types, but structs where all fields are exposed all have the same semantics as each other. Those semantics differ from classes, but for cases where they're useful, they have no equal.
Incidentally, much of the bad reps "mutable structs" got was a result of the fact that mutating struct members other than exposed fields would often generate bogus code if applied to read-only structures. If you avoid having struct members which modify fields of this [it's perfectly safe for static struct methods to modify fields of structures received as ref parameters], those dangers don't apply.
I simply just changed the struct definition to a class.
I trying to emit dynamic method that sets fields of class by some values and when type of regular field is struct I want to set field with new struct like this: var myStruct = new SomeStruct( );.
But I can't to find default constructor of that struct.
var type = valueForField.GetType ( );
if( type.IsValueType && !type.IsPrimitive && !type.IsEnum )
{
emit
.ldarg_0
.newobj ( type.GetConstructor( Type.EmptyTypes ) )
.stfld ( field );
continue;
}
It fails at line .newobj ( type.GetConstructor( Type.EmptyTypes ) ) because of passing null to newobj function
Can anybody tell me how to emit new structure creation through it default constructor?
Use initobj
.ldarg_0
.ldflda (field)
.initobj (type)
From msdn:
Value types are not usually created using newobj. They are usually allocated either as arguments or local variables, using newarr (for zero-based, one-dimensional arrays), or as fields of objects. Once allocated, they are initialized using Initobj.
Structs can't have a real parameterless constructor. They have an implicit default constructor that's equivalent to default(T).
It seems like the IL equivalent of default(T) is initobj
Unlike Newobj, initobj does not call the constructor method. Initobj is intended for initializing value types, while newobj is used to allocate and initialize objects.
Is there a way to find the QMetaObject instance of a class, given the class name? what I like to do is to load objects from disk, but for this to happen, I need a way to retrieve a QMetaObject instance using the name of a class, in order to use the QMetaObject to create an instance.
You should be able to do this with QMetaType. You might need Q_DECLARE_META_TYPE() and/or qRegisterMetaType() to make your types known. Then it should work roughly like in this example from the link:
int id = QMetaType::type("MyClass");
if (id == 0) {
void *myClassPtr = QMetaType::construct(id);
...
QMetaType::destroy(id, myClassPtr);
myClassPtr = 0;
}
I have been facing the same problem recently. I needed the metaobject without having to create an instance of the class itself. Best I could do is to create a global / static function that retrieves the qmetaobject given the class name. I achieved this by using QObject::staticMetaObject.
QMetaObject GetMetaObjectByClassName(QString strClassName)
{
QMetaObject metaObj;
if (strClassName.compare("MyClass1") == 0)
{
metaObj = MyClass1::staticMetaObject;
}
else if (strClassName.compare("MyClass2") == 0)
{
metaObj = MyClass2::staticMetaObject;
}
else if (strClassName.compare("MyClass3") == 0)
{
metaObj = MyClass3::staticMetaObject;
}
else if (strClassName.compare("MyClass4") == 0)
{
metaObj = MyClass4::staticMetaObject;
}
else if (strClassName.compare("MyClass5") == 0)
{
metaObj = MyClass5::staticMetaObject;
}
// and so on, you get the idea ...
return metaObj;
}
See : http://doc.qt.io/qt-5/qobject.html#staticMetaObject-var
If somebody has a better option, please share !
You can store the MetaClass instances you will need in a Hash or Map, and then retrieve them via whatever name you stored them under
For your case the appropriate solution can be using Qt plugin mechanism. It offers functionality to easily load shared/dynamic library and check if it contains implementation of some desired interface, if so - create the instance. Details can be found here: How to Create Qt Plugins
You can also take a look at the function: QMetaType::metaObjectForType which
returns QMetaType::metaObject for type
Update: That's my code, it create a class by class name. (Note that the class must be registered with qRegisterMetaType (or is QObject base)
int typeId = QMetaType::type("MyClassName");
const QMetaObject *metaObject = QMetaType::metaObjectForType(typeId);
QObject *o = metaObject->newInstance();
MyClassName *myObj = qobject_cast<MyClassName*>(o);
Update 2: I have forgot to say. Yout class's constructor must be marked as Q_INVOKABLE
I am a Java programmer and need to work on a Flex/ActionScript project right now. I got an example of using ITreeDataDesriptor from Flex 3 Cookbook, but there is one line of actionscript code that's hard for me to understand. I appreciate if someone could explain this a little further.
public function getData(node:Object, model:Object=null):Object
{
if (node is Office) {
return {children:{label:node.name, label:node.address}};
}
}
The part that I didn't understand was "{children:{label:node.name, label:node.address}}". Office is simply a value object that contains two String properties: name and address.
The following return expression (modified from the question) ...
return {children:{label:node.name, body:node.address}}
... is functionally equivalent to this code ...
var obj:Object = new Object();
obj.children = new Object();
obj.children.label = node.name;
obj.children.body = node.address;
return obj;
The anonymous object returned in the question code complicates matters because it defines a property twice. In that case, the first declaration is used, and the subsequent one(s) are ignored. No compile-time or runtime error is thrown.
I think in Java you would call that a map or an associative array. In Javascript and Actionscript you can say this to create an object with certain properties:
var myobject = {
'prop1': 100,
'prop2': {
'a': 1
}
}
trace( myobject.prop1 ); // 100
trace( myobject.prop2.a ); // 1
In your example it's just returned as a nameless object.
return {children:{label:node.name, label:node.address}};
Means you are returning a new Object. The {} are the Object's constructor, and in this case its an Anonymous object.
Thank you both for the quick response. So if I understand your explanations correctly, the return statement is returning an anonymous object, and this object has only one property named "children", which is again an associative array - ok, here is the part I don't quite understand still, it seems that both properties in this array are named "label", is this allowed?
Data binding in ActionScript is really cool. But what if I want to refactor a big switch or if statement inside the curly braces into a function, for example:
{person.gender == 'male' ? 'Mr.' : 'Ms.'}
into:
{salutation(person)}
The compiler doesn't let me do that. I know about properties and I could write getters and setters on the person object. But since I am using inlined JSON objects now that's not convenient(I think). What are other good ways to refactor this code?
To answer Matt's comment. The data type of person is just plain Object. It was decoded from JSON format coming from a service call.
You'll need to make the Person class (assuming you have one) bindable in order for this to work.
However, since you are saying you're using JSON objects, I'm assuming you just have anonymous objects that were parsed from a JSON string. In that case, I'm pretty sure that won't work. You'll need to create a strongly typed object that has bindable properties.
Just FYI: to avoid having to write custom JSON parsers for every object you want to create, you can create strong typed objects from vanilla objects using a bytearray trick:
public static function toInstance( object:Object, clazz:Class ):* {
var bytes:ByteArray = new ByteArray();
bytes.objectEncoding = ObjectEncoding.AMF0;
// Find the objects and byetArray.writeObject them, adding in the
// class configuration variable name -- essentially, we're constructing
// and AMF packet here that contains the class information so that
// we can simplly byteArray.readObject the sucker for the translation
// Write out the bytes of the original object
var objBytes:ByteArray = new ByteArray();
objBytes.objectEncoding = ObjectEncoding.AMF0;
objBytes.writeObject( object );
// Register all of the classes so they can be decoded via AMF
var typeInfo:XML = describeType( clazz );
var fullyQualifiedName:String = typeInfo.#name.toString().replace( /::/, "." );
registerClassAlias( fullyQualifiedName, clazz );
// Write the new object information starting with the class information
var len:int = fullyQualifiedName.length;
bytes.writeByte( 0x10 ); // 0x10 is AMF0 for "typed object (class instance)"
bytes.writeUTF( fullyQualifiedName );
// After the class name is set up, write the rest of the object
bytes.writeBytes( objBytes, 1 );
// Read in the object with the class property added and return that
bytes.position = 0;
// This generates some ReferenceErrors of the object being passed in
// has properties that aren't in the class instance, and generates TypeErrors
// when property values cannot be converted to correct values (such as false
// being the value, when it needs to be a Date instead). However, these
// errors are not thrown at runtime (and only appear in trace ouput when
// debugging), so a try/catch block isn't necessary. I'm not sure if this
// classifies as a bug or not... but I wanted to explain why if you debug
// you might seem some TypeError or ReferenceError items appear.
var result:* = bytes.readObject();
return result;
}