JsonCPP throwing a logic error:requires objectValue or nullValue - c++

void exp::example(std::string &a, std::string &b)
{
if (m_root.isObject() && m_root.isMember(a))
{
if (m_root[a].isMember(b))
{
m_root[a].append(b);
}
}
else
{
m_root[a] = Json::arrayValue;
m_root[a].append(b);
}
}
(m_root is defind in the hpp)
When I'm running this code I get the logic error:
in Json::Value::find(key, end, found): requires objectValue or nullValue.
I found out that I got this error from this if:
if (m_root[a].isMember(b))
I don't understand why do I get this error there, I used the same function in the if above him and I didn't get this error.
P.S the function is working until it enter the nested if, example:
a
b
m_root
"hey"
"a1"
{"hey":["a1"]}
"bye"
"a2"
{"hey":["a1"], "bye":["b1"]}
"cye"
"a3"
{"hey":["a1"], "bye":["b1"], "cye":["a3"]}
"hey"
"a4"
error: in Json::Value::find(key, end, found): requires objectValue or nullValue
I get the error only in the 4th call.
I appreciate your help!

On the 4th iteration you access the m_root["hey"] object which is of type arrayValue. Those values are not supported by the isMember method.
You'll have to find the value in the array in another way. I suggest iterating over the array, in something like:
bool is_inside_array(const Json::Value &json_array, const string& value_to_find)
{
for (const Json::Value& array_value: json_array) {
if (array_value.asString() == value_to_find) {
return true;
}
}
return false;
}
Then replace the inner if with:
if (is_inside_array(m_root[a], b))

Related

Error: no matching function for call to 'std::vector<Movie>::erase(size_t&)'

I am currently learning C++ / making a simple movie database. I use classes and I have a method Delete Movie. Unfortunately, when I try to delete object Movie from a vector database, there's this error.
for (size_t num {}; num < database.size(); ++num)
if ((database.at(num)).getname() == name) {
database.erase(num); // <--- error here
return true;
}
Can someone hopefully tell me, what am I making wrong?
If you need more information, I can send the whole file.
erase accepts iterator as said pptaszni
Replace your for code by this:
auto it = std::remove_if(database.begin(), database.end(), [&name](const Movie& item) -> bool { return item.getname() == name; });
database.erase(it, database.end());
Or change just 1 line (database.erase(num)) like this:
database.erase(database.begin() + num);

for_each not returning (boolean) value

I have a program to verify if an IPv4 address entered as string is in valid dotted-quad notation.
The problem I am facing is that I'm not able to return (exit) function once I detect error. As per cppreference documentation for_each returns UnaryFunction. I tried using any_of and all_of but they require me using an loop (range-based loop) inside my lambda function which I'm trying to avoid. Am I missing something or it is not possible to return value in for_each.
vector<string> ipExplode;
string ip;
bool inValidIp = false;
cout << "Server IP : ";
cin >> ip;
trim(ip);
ipExplode = explode(ip, '.');
if(not for_each(ipExplode.begin(), ipExplode.end(), [](const string& str) -> bool{
int32_t ipNum;
if(regex_search(str, regex("\\D+")))
return false;
try
{
ipNum = stoi(str);
if(ipNum < 0 or ipNum > 255)
return false;
}
catch (std::exception& ex)
{
return false;
}
}))
return false;
from for_each:
If f returns a result, the result is ignored.
i.e. there is no point in returning a value from your for_each lambda.
A good choice here is all_of, which accepts a UnaryPredicate rather than a UnaryFunction, since you want to make sure that all of the parts of the string pass the lambda successfully:
bool isValid = std::all_of(ipExplode.begin(), ipExplode.end(), [](const std::string& str) -> bool{
if(regex_search(str, regex("\\D+")))
return false;
try
{
int32_t ipNum = stoi(str);
if(ipNum < 0 or ipNum > 255)
return false;
}
catch (std::exception& ex)
{
return false;
}
return true;
});
all_of will stop iterating once an invalid part is found.
Am I missing something or it is not possible to return value in for_each.
for_each does return the UnaryFunction. But if you put a unary function to if expression, its meaningless.
In your case, a lambda without capturing can implicitly convert to a function pointer. A non-null function pointer as a boolean value is always true. Thus your
if(not for_each( /* ... */ ))
will be evaluated to false all the time.
As commentators and other answerers have already written, std::all_of is what you want here.
You shouldn't use for_each anyway. Replace it by the ranged-based for and it all becomes so much simpler and elegant. Put it all in a function and there you go:
auto is_ip_valid(const std::vector<std::string>& ipExplode)
{
for (auto&& str : ipExplode)
{
// ...
}
}

Rapidjson returning reference to Document Value

I'm having some trouble with the following method and I need some help trying to figure out what I am doing wrong.
I want to return a reference to a Value in a document. I am passing the Document from outside the function so that when I read a json file into it I don't "lose it".
const rapidjson::Value& CTestManager::GetOperations(rapidjson::Document& document)
{
const Value Null(kObjectType);
if (m_Tests.empty())
return Null;
if (m_current > m_Tests.size() - 1)
return Null;
Test& the_test = m_Tests[m_current];
CMyFile fp(the_test.file.c_str()); // non-Windows use "r"
if (!fp.is_open())
return Null;
u32 operations_count = 0;
CFileBuffer json(fp);
FileReadStream is(fp.native_handle(), json, json.size());
if (document.ParseInsitu<kParseCommentsFlag>(json).HasParseError())
{
(...)
}
else
{
if (!document.IsObject())
{
(...)
}
else
{
auto tests = document.FindMember("td_tests");
if (tests != document.MemberEnd())
{
for (SizeType i = 0; i < tests->value.Size(); i++)
{
const Value& test = tests->value[i];
if (test["id"].GetInt() == the_test.id)
{
auto it = test.FindMember("operations");
if (it != test.MemberEnd())
{
//return it->value; is this legitimate?
return test["operations"];
}
return Null;
}
}
}
}
}
return Null;
}
Which I am calling like this:
Document document;
auto operations = TestManager().GetOperations(document);
When I inspect the value of test["operations"] inside the function I can see everything I would expect (debug code removed from the abode code).
When I inspect the returned value outside the function I can see that it's an array (which I expect). the member count int the array is correct as well, but when print it out, I only see garbage instead.
When I "print" the Value to a string inside the methods, I get what I expect (i.e. a well formated json), but when I do it outside all keys show up as "IIIIIIII" and values that aren't strings show up correctly.
rapidjson::StringBuffer strbuf2;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer2(strbuf2);
ops->Accept(writer2);
As this didn't work I decided to change the method to receive a Value as a parameter and do a deep copy into it like this
u32 CTestManager::GetOperationsEx(rapidjson::Document& document, rapidjson::Value& operations)
{
(...)
if (document.ParseInsitu<kParseCommentsFlag>(json).HasParseError())
{
(...)
}
else
{
if (!document.IsObject())
{
(...)
}
else
{
auto tests = document.FindMember("tests");
if (tests != document.MemberEnd())
{
for (SizeType i = 0; i < tests->value.Size(); i++)
{
const Value& test = tests->value[i];
if (test["id"].GetInt() == the_test.id)
{
const Value& opv = test["operations"];
Document::AllocatorType& allocator = document.GetAllocator();
operations.CopyFrom(opv, allocator); //would Swap work?
return operations.Size();
}
}
}
}
}
return 0;
}
Which I'm calling like this:
Document document;
Value operations(kObjectType);
u32 count = TestManager().GetOperationsEx(document, operations);
But... I get same thing!!!!
I know that it's going to be something silly but I can't put my hands on it!
Any ideas?
The problem in this case lies with the use of ParseInSitu. When any of the GetOperations exist the CFileBuffer loses scope and is cleaned up. Because the json is being parsed in-situ when the buffer to the file goes, so goes the data.

boost::remove_if causing an error (Read-only variable is not assignable)

My method looks like this, getting an error during compilation "Read-only variable is not assignable" in vector.
What can be the problem?
int DownloadManager::RemoveDownload(const char *escapedTitle, const char *fileId)
{
boost::remove_if(Core::defaultCore().GetSocketsQueue()->GetQueue(), [&](SocketConnection* socket) {
if (strcmp(escapedTitle, socket->GetDownload()->escaped_title.c_str()) == 0 && strcmp(fileId, socket->GetDownload()->fileId.c_str()) == 0)
{
Core::defaultCore().GetDownloadQueue()->Remove(socket->GetDownload());
return true;
}
return false;
});
return 0;
}
Pasted just to show what GetQueue() above looks like.
std::vector<SocketConnection*> GetQueue()
{
return this->sockets_queue;
}
You should return reference from GetQueue, since now you are trying to remove from temporary variable, that is not allowed, because remove_if first parameter is expected to be reference, there is no conversion from temporary-variable to reference.

Why Removing item from list in this way is impossible?

I have a problem that as i try to remove item from any list in following way i am unable to do that ... why is that so the error is "use of unassigned local variable" where is it is assigned as shown below:
public void RemoveFrmList(int ProdId)
{
int _index;
foreach (Products item in BoughtItems)
{
if (item.ProductID == ProdId)
{
_index = BoughtItems.IndexOf(item);
}
}
BoughtItems.RemoveAt(_index);
}
what can be done to remove this error?
the code inside the if statement does not necessarily occur. Initialize _index to -1 or some "not found" indicating value and the error should go away.
What is BoughtItems ? If it's List<T> just use RemoveAll
public void RemoveFrmList(int ProdId)
{
BoughtItems.RemoveAll( item => item.ProductID == ProdId );
}
Slightly offtopic but why is RemoveFrmLis missing the o? It just hurts readability. Use the full word.
_index is unassigned until you go in the loop. But if BoughtItems has no Product items, you will have a unnassigned variable _index. Or maybe you will never get an item with item.ProductID == ProdID.
So in other words:
int _index;
foreach (Products item in BoughtItems)
{
//Code here is not executed during runtime for reasons stated above.
}
BoughtItems.RemoveAt(_index); //error here because _index was not assigned!
To fix it, you could do something like
int _index = -1;
foreach (...)
{
//...
}
if (_index != -1){
BoughtItems.RemoveAt(_index);
}
else
{
//handle case if needed
}