JsonCpp - modify an array of objects - c++

I have a following array of objects in JsonCpp::Value:
[{"foo": "bar", "baz": ["Hello", "World"]},
{"Hello": "99bottles", "baz": ["bar", "foo"]},
{"beer": "hello", "world": ["foo"]}.... ]
I have to iterate over them and alternate them (remove some elements, add another one).
I can easily iterate over JsonArray with:
for (Json::Value::ArrayIndex i = 0; i != array.size(); i++) {
doc[i] = Json::Value();
Json::Value result = array.get(i, Json::Value());
std::cout<<"-------------------"<<std::endl;
std::cout<<result.toStyledString()<<std::endl;
}
But array.get() returns a copy of object. I won't be able to modify the object itself. I can create a new array and fill it with new objects based on values from the original one but it will be very costly.
Is it possible to achieve my goal with JsonCpp "in place"? And avoid additional memory overhead?

You are using get() which must return a value instead of a reference, because you can call with with an invalid i and it will return the default value you provide. I.e. for an array of size 2, you should be able to call array.get(17, Json::Value()) and you'll get back a default initialized Json::Value.
If you're certain the element exists, which is the case here, you can use array[i], which will give you a reference. Note that you need to change the type of result to Json::Value & as well, otherwise you'll still get a copy.
Note that this is all shown and explained in the API documentation for JsonCpp. I've never used this library myself, all the above info I got from that page.

Related

Returning a filtered range

I'm looking at filtering ranges, and getting a little confused. In D, I can write this code:
import std.stdio;
import std.range;
import std.algorithm;
auto filterNums(int[] vals)
{
int limit = 3;
return filter!(n => n >limit)(vals);
}
int main()
{
int[] nums = [1,2,3,4,5];
auto flt = filterNums(nums);
foreach(n;flt)
{
writeln(n);
}
return 0;
}
which gives the expected output of:
4
5
But this doesn't seem to be terribly safe code. If the filter is lazy evaluating, how does it know that limit is 3, once the local variable goes out of scope? Is my code just lucky that nothing else has over-ridden limit in memory? Also is the passed variable nums a reference, or a copied value: if a value, is the filter making its own copy?
Or perhaps I am not using filter in the correct way?
int is a value type, so the filter lambda receives a copy of it. If there were any scoping issues, the compiler would warn you.
int[] nums is a dynamic array managed by D's runtime. It consists of two parts: a value part, which contains its length and a pointer, which points to the dynamic part on the heap (where the ints are stored). The length and pointer itself are passed by value, which means appending or removing will not affect the original, but editing an element e.g. vals[1] = 1 would. To pass all of it by reference, you would use
filterNums(ref int[] vals).
Either way, the garbage collector keeps it around as long as it's needed, in this case it is stored in the filter construct.

nlohmann JSON: serialize an array like int*?

I need to serialize an array of int into a json object.
int* myObject = new int[5] { ... }
I cannot find any solution to this. Even using a vector.
Also, I cannot put my json "manually", since this array isnt fixed.
For this, I would use the basic_json::array() helper method that constructs a json array, and the basic_json::push_back(val) member function for appending values to an array. In this example, the_size refers to the number of elements in myObject.
auto arr = nlohmann::json::array();
for (int i = 0; i < the_size; ++i){
arr.push_back(myObject[i]);
}
In the future, I would recommend that you browse the documentation of a tool like this, to see if you can find anything helpful. Most things you would want to know about a software library should be answerable in the documentation.

Unable to reorder elements in array - RapidJSON

How to reorder elements in rapidjson array? I have JSON doc that has Test array with three objects as below
{
"Test":[
{
"a":1,
"b":"DEMO"
},
{
"c":2,
"d":"DEMO1"
},
{
"e":5,
"f":"DEMO2"
}
]
}
Question- How to add one below object at the second position in above Test array without deleting existing object?
{
"x":3,
"y":"DEMO3"
}
Since Test is an array, while it is possible to access a specific cell (ie- Test[1] = something) it's not possible to push the rest of the array without rewriting it. (Test[1] will overwrite whatever's in there)
This behaviour is possible with vectors though, so perhaps a possible solution could be to copy Test to a temporary vector, perform the operation there and then convert back to array.
From what I've seen it's not possible to use vectors with rapidjson.

Select a random object from an array of objects

I'd like to implement a function that selects a random object from an array of objects and returns it to me. It should be something like (in C++ instead of psuedocode):
getRandomObject(objectList) {
return objectList[int(random(length of objectList))];
}
My current code looks like this, but doesn't seem to work:
//definition of random selector
object getRandomObject(Object* objectList) {
return objectList[int(ofRandom(0, sizeof(objectList)))];
};
//create a pointer for the listOfObjects
object* listOfObjects;
//create an empty object to put the randomly selected object in
object randomObject;
//later in the code, populate the array:
object* listOfObjects[] = {
new Object(),
new Object(),
new Object()
};
//select random object
randomObject = getRandomObject(listOfObjects);
But this seems to return a segmentation fault. A few problems I've noticed:
sizeof() returns the size of the pointer in getRandomObject, not the size of the array. is there a good way to get the size of the array? It might involves not using a float* pointer for the array. Is this a good use case for vectors?
I think that much of the problem lies in how I'm creating my arrays, and not so much in how I'm selecting the random object from them. I'm relatively new to C++ (coming from a Java background), so much of pointers / references / memory management in general is new to me.
thanks!
I see one definite problem and one possible one. The definite problem is that sizeof(objectList) returns the size of the objectList pointer, which will be 4 or 8 on most platforms. It does not return the number of elements in the array, objectList. Either pass in the length of the array or use std::vector or std::array.
The second possible problem relates to ofRandom. Make sure that ofRandom(a,b) returns numbers >= a, but strictly < b. If it returns values <= b, then you'll need to us ofRandom(0, objectVector.size() - 1). Typically, functions like this are written to return values strictly < b, but you should check.
C++ has an array template class that you may want to consider using. Check out the documentation here:
http://www.cplusplus.com/reference/array/array/
This type has a method, size(), that will return the length of the array.
When the sizeof operator is applied to an array, it yields the total
number of bytes in that array, not the size of the pointer represented
by the array identifier.
Quote
So you take the space alocated for your whole array and divide by the memory need just for one element: sizeof(objectList) / sizeof(*objectList).
Mr Fooz noticed issues that cause a segfault.
Other compilation issues are:
listOfObjects is declared with 2 different types: object* and object*[3] while getRandomObject expects a type Object*.
listOfObjects[] contains elements of type object* while getRandomObject reads elements of type Object and returns object.

Initialize an object array in c++ with a special value

I am an intermediate java programmer and I am used to relaying on the null value in java for cheking if objets are initialized with some reference to instanced object in memory. I want to do something similar in c++ but I do not have a clear idea about how I can achieve it. I want to initialize a user array - user is a class I have defined - so I can check if the actual position in the array does contain an object or it is free.
I have tried to use the null definition in c++ but found out that it is simply a "-1" int value and I could not use it properly. So basically I need something to distinguish between a free position in my array and an ocuppied one.
Additionally I might be interested in having an extra value to distinguish a position that contained a removed user, since I am planning to just mark the desired position with a special mark as a freed position when it comes to the method that remove a user from the array.
For the curious ones, I am implementing a simple hash set and the remove method in my class just mark the position of the element to remove instead of doing some restruction.
First of all null definition is not -1 but 0. Assuming you have something like
class User
{
};
User RemovedClass;
you can have something like this
User *arr[3];
arr[0] = new User();
arr[1] = 0;
arr[2] = &RemovedClass;
Here 0 is a new User, 1 is java null equivalent , 2 is marker for deleted class.
EDIT
Typically when you see User array in java you will have to map it to a User* array in C++.
After these operations.
User a;
User b;
a = b;
in java a and b will refer to the same User. In C++ such code will yield to a and b referring to two different User objects.
I think there are some concept you need to understand.
Unlike Java, when you are creating an N-element array of User, it is NOT an array of reference. It is really a piece of memory containing actual N user, which is already created and initialized (i.e. constructor already run). (Well, there are more advanced topics like placement-new but I think it is not really what you are looking for yet)
So it is somehow contradicting if you said you have an "array of User" and want to keep track if certain position is initialized.
Unless:
You are not creating array of User, but Array of "Pointer to User" (or other reference like auto_ptr). By such way, it is meaningful to say certain element is "null"; or
Your "initialize" do not mean creating an object instance, but an explicit initialization action (like executing an init() method of an User instance). By such way, it is meaningful to say certain element is "not initialized".
(First of all, as you are writing C++, I shall recommend you to use std::vector, not array. However I am using array in this answer, as to stick close to your question)
For case 1, it is strict forward, simply use NULL (avoid using 0, because, although NULL is defined as 0 in most system, using NULL actually makes the code more readable and more portable):
User* user[10] = {NULL}; // array of 10 pointer-to-User
user[0] = new User(...);
assert (user[0] != NULL);
assert (user[1] == NULL);
For case 2, you have many other choice, like keeping another array of boolean to keep the "initialized" flag, or have a wrapper over User for such extra flag, or simply add such flag into your User class, etc.
e.g.
User user[10]; // 10 element of User, which all of them is already created
//assume you have extra flag in User
user[0].init(...); // explicity do some init work on user[0]
//......
if (! user[5].isInitialized()) {
user[5].init(...);
}
(honestly I think case 2 is not really what you are looking for)
I use boost::optional:
boost::optional<int> a;
if (!a) { std::cout << "no a!"; }
a = 5;
if (a) { std::cout << "a = " << *a; }
a = boost::none;
if (!a) { std::cout << "no a!"; }