I have a jsoncpp value that I want to serialize. The most straightforward way is like this:
Json::Value val; // population is left as an exercise for the reader
std::string str = Json::FastWriter().write(val);
The problem is that FastWriter is deprecated, and I can't tolerate compiler warnings. According to the less-than-intuitive documentation, I'm supposed to use StreamWriterBuilder instead:
Json::StreamWriterBuilder builder;
builder["commentStyle"] = "None";
builder["indentation"] = "";
std::unique_ptr<Json::StreamWriter> writer( builder.newStreamWriter() );
std::ostringstream os;
writer->write(val, &os);
std::string str = os.str();
Surely this can't be "better"? I'm assuming the fault lies with me and there is a straightforward way to perform minimal serialization (without extraneous whitespace).
This shows a slightly more compact form (although it appears to simply wrap the above in a function call).
Json::StreamWriterBuilder builder;
builder["indentation"] = ""; // assume default for comments is None
std::string str = Json::writeString(builder, val);
Is that the right way now?
You're doing it the right way.
The second example is just a shorthand for the first — in both instances, a builder dynamically allocates a writer, the writer is used and then the writer is freed.
Why the older FastWriter implementation was deprecated I could not say. Personally I miss it a bit. But a factory is more flexible and permits different implementations slotting into the same suite of functions. You'd have to ask the JsonCpp developers whether that was the core of their decision.
If you always want to write with the same settings (e.g. your ["indentation"] = ""), you can supply a Json::Value representing the settings to Json::StreamWriterBuilder::setDefault, then writing strings doesn't need to name Json::StreamWriterBuilder again (but does default construct one)
Startup
Json::Value streamWriterSettings{R"({ "indentation" : "" })"};
Json::StreamWriterBuilder::setDefault(&streamWriterSettings);
Usage
std::string str = Json::writeString({}, val);
Related
In a codebase I'm working on I keep encountering code like this:
std::string& getSomeValue(std::string& str)
{
str = "Hello World!";
return str;
}
Is there any benefit to writing this over:
std::string getSomeValue()
{
return "Hello World!";
}
I appreciate that there is no string construction in the function, but the many disadvantages outway that small benefit. Especially since elision and moving should remove most of the overhead.
It leads to undefined behaviour if called as
std::string s = getSomeValue(s);
It's untidy to write the following, and s now can't be const:
std::string s;
getSomeValue(s);
You can't pass a temporary, e.g.
std::string s = getSomeValue("");
You can't change std::string& getSomeValue(std::string& str) into std::string getSomeValue(). That would break the API and ABI. Existing code using that function would need to be changed.
So one benefit is maintaining API/ABI compatibility. As to why this was written this way, it's probably pre-C++11 code.
However, an overload could be introduced, keeping the old function and introducing the new, better form. The old one can then be marked deprecated:
[[deprecated("unsafe, use getSomeValue() without argument instead")]]
std::string& getSomeValue(std::string& str);
Use of the old function will then generate a compiler warning and the code can be changed over time to adopt the new function.
For deserializing JSON into a c++ class, I'm using Cereal, which uses RapidJSON. As expected, c++ std::string can't have a null value. But other platforms do support null for strings (.NET SQL etc) and I get JSON from them with null values for strings. I need to tolerate this, and just make an empty string for nulls. What's the best way to do that?
I default to string substitute on the JSON changing nulls to "" like the following, but it is not a clean solution.
#include <cereal/archives/json.hpp>
#include <boost/algorithm/string.hpp>
// i.e. substitue all ":null with ":"" Like {"key":null} into {"key":""}
boost::replace_all(json, "\":null", "\":\"\"");
auto r = std::make_shared<R>();
std::stringstream ss(json);
{
cereal::JSONInputArchive archive(ss);
r->serialize(archive);
}
In case someone looks for this answer based on the exception generated by Cereal, it is: "rapidjson internal assertion failure: IsString()"
in cereal-1.1.2\include\cereal\external\rapidjson\document.h
change this
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
to this
const Ch* GetString() const { if (IsNull_()) return ""; RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
I'm not proposing this should be changed in the cereal source because some people may want strict type checking like the original
I am using JsonCpp to build a JSON object. Once the object is built, is there a way I can get the object as an std::string?
You can use a Json::Writer to do exactly this, since I assume you want to save it somewhere so you don't want human readable output, your best bet would be to use a Json::FastWriter and then you can call the write method with the parameter of your Json::Value (ie. your root) and then that simply returns a std::string like so:
Json::FastWriter fastWriter;
std::string output = fastWriter.write(root);
Json::Writer is deprecated. Use Json::StreamWriter or Json::StreamWriterBuilder instead.
Json::writeString writes into a stringstream and then returns a string:
Json::Value json = ...;
Json::StreamWriterBuilder builder;
builder["indentation"] = ""; // If you want whitespace-less output
const std::string output = Json::writeString(builder, json);
Kudos to cdunn2001's answer here: How to get JsonCPP values as strings?
You can also use the method toStyledString().
jsonValue.toStyledString();
The method "toStyledString()" converts any value to a formatted string.
See also the link: doc for toStyledString
If your Json::value is of string type, e.g. "bar" in the following json
{
"foo": "bar"
}
You can use Json::Value.asString to get the value of bar without extra quotes(which will be added if you use StringWriterBuilder). Here is an example:
Json::Value rootJsonValue;
rootJsonValue["foo"] = "bar";
std::string s = rootJsonValue["foo"].asString();
std::cout << s << std::endl; // bar
In my context, I instead used a simple .asString() at the end of my json value object. As #Searene said, it gets rid of the extra quotes that you don't necessary wants if you want to process it after.
Json::Value credentials;
Json::Reader reader;
// Catch the error if wanted for the reader if wanted.
reader.parse(request.body(), credentials);
std::string usager, password;
usager = credentials["usager"].asString();
password = credentials["password"].asString();
If the value is a int instead of a string, .asInt() works great as well.
This little helper might do.
//////////////////////////////////////////////////
// json.asString()
//
std::string JsonAsString(const Json::Value &json)
{
std::string result;
Json::StreamWriterBuilder wbuilder;
wbuilder["indentation"] = ""; // Optional
result = Json::writeString(wbuilder, json);
return result;
}
I'm currently working on a larger project, where the "logic" is implemented in standard C++ with all strings being handled with std::wstring and the UI part is implemented using Qt and thus necessarily QString (Bonus question: is this true?).
What is the best way to connect those two worlds?
I know I can use something like
std::wstring wideString;
QString qtString = QString::fromStdWString(wideString);
but I'm wondering if there is a nicer way with less typing involved. A user defined operator came to my mind, but I'm not experienced enough to tackle that on my own.
Would be glad if anyone could point me in the right direction.
It's a good idea to use QString::fromStdWString but (!!!) if Qt was compiled with exactly the same STL headers as your project. If not - you can get a lot of fun, catching a bug.
If you don't sure that both STL headers are the same use QString::fromWCharArray:
std::wstring wideString;
QString qtString = QString::fromWCharArray( wideString.c_str() );
Update: answering to #juzzlin:
Lets imagine that Qt was build with the STL containing the following std::wstring:
class wstring { // I know, that there's no such class, but I'm shure you'll understand what I want to say
wchar_t * m_ptr;
size_t m_length;
...
};
and you have the STL containing the following std::wstring:
class wstring {
wchar_t * m_ptr;
wchar_t * m_the_end;
...
};
If you'll give your std::wstring to Qt, it will interpret m_the_end pointer as the length of the string, and
you can get a lot of fun, catching a bug
I think a user defined conversion is what you're looking for, and from what I can gather, it should look something like this:
class foo
{
public:
operator QString(std::wstring& ws)
{
return QString::fromStdWString(ws);
}
}
maybe make a inline function QString toQString(std::wstring string) to make it 'less to type' ...
but to be honest ... thats not the big effort at all to write it from time to time ;)
soo long zai
I am working in C++ with two large pieces of code, one done in "C style" and one in "C++ style".
The C-type code has functions that return const char* and the C++ code has in numerous places things like
const char* somecstylefunction();
...
std::string imacppstring = somecstylefunction();
where it is constructing the string from a const char* returned by the C style code.
This worked until the C style code changed and started returning NULL pointers sometimes. This of course causes seg faults.
There is a lot of code around and so I would like to most parsimonious way fix to this problem. The expected behavior is that imacppstring would be the empty string in this case. Is there a nice, slick solution to this?
Update
The const char* returned by these functions are always pointers to static strings. They were used mostly to pass informative messages (destined for logging most likely) about any unexpected behavior in the function. It was decided that having these return NULL on "nothing to report" was nice, because then you could use the return value as a conditional, i.e.
if (somecstylefunction()) do_something;
whereas before the functions returned the static string "";
Whether this was a good idea, I'm not going to touch this code and it's not up to me anyway.
What I wanted to avoid was tracking down every string initialization to add a wrapper function.
Probably the best thing to do is to fix the C library functions to their pre-breaking change behavior. but maybe you don't have control over that library.
The second thing to consider is to change all the instances where you're depending on the C lib functions returning an empty string to use a wrapper function that'll 'fix up' the NULL pointers:
const char* nullToEmpty( char const* s)
{
return (s ? s : "");
}
So now
std::string imacppstring = somecstylefunction();
might look like:
std::string imacppstring( nullToEmpty( somecstylefunction());
If that's unacceptable (it might be a lot of busy work, but it should be a one-time mechanical change), you could implement a 'parallel' library that has the same names as the C lib you're currently using, with those functions simply calling the original C lib functions and fixing the NULL pointers as appropriate. You'd need to play some tricky games with headers, the linker, and/or C++ namespaces to get this to work, and this has a huge potential for causing confusion down the road, so I'd think hard before going down that road.
But something like the following might get you started:
// .h file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction();
}
// .cpp file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction() {
const char* p = ::somecstylefunction();
return (p ? p : "");
}
}
Now you just have to add that header to the .cpp files that are currently calling calling the C lib functions (and probably remove the header for the C lib) and add a
using namespace clib_fixer;
to the .cpp file using those functions.
That might not be too bad. Maybe.
Well, without changing every place where a C++ std::string is initialized directly from a C function call (to add the null-pointer check), the only solution would be to prohibit your C functions from returning null pointers.
In GCC compiler, you can use a compiler extension "Conditionals with Omitted Operands" to create a wrapper macro for your C function
#define somecstylefunction() (somecstylefunction() ? : "")
but in general case I would advise against that.
I suppose you could just add a wrapper function which tests for NULL, and returns an empty std::string. But more importantly, why are your C functions now returning NULL? What does a NULL pointer indicate? If it indicates a serious error, you might want your wrapper function to throw an exception.
Or to be safe, you could just check for NULL, handle the NULL case, and only then construct an std::string.
const char* s = somecstylefunction();
if (!s) explode();
std::string str(s);
For a portable solution:
(a) define your own string type. The biggest part is a search and replace over the entire project - that can be simple if it's always std::string, or big one-time pain. (I'd make the sole requriement that it's Liskov-substitutable for a std::string, but also constructs an empty string from an null char *.
The easiest implementation is inheriting publicly from std::string. Even though that's frowned upon (for understandable reasons), it would be ok in this case, and also help with 3rd party libraries expecting a std::string, as well as debug tools. Alternatively, aggegate and forward - yuck.
(b) #define std::string to be your own string type. Risky, not recommended. I wouldn't do it unless I knew the codebases involved very well and saves you tons of work (and I'd add some disclaimers to protect the remains of my reputation ;))
(c) I've worked around a few such cases by re-#define'ing the offensive type to some utility class only for the purpose of the include (so the #define is much more limited in scope). However, I have no idea how to do that for a char *.
(d) Write an import wrapper. If the C library headers have a rather regular layout, and/or you know someone who has some experience parsing C++ code, you might be able to generate a "wrapper header".
(e) ask the library owner to make the "Null string" value configurable at least at compile time. (An acceptable request since switching to 0 can break compatibility as well in other scenarios) You might even offer to submit the change yourself if that's less work for you!
You could wrap all your calls to C-stlye functions in something like this...
std::string makeCppString(const char* cStr)
{
return cStr ? std::string(cStr) : std::string("");
}
Then wherever you have:
std::string imacppstring = somecstylefunction();
replace it with:
std::string imacppstring = makeCppString( somecystylefunction() );
Of course, this assumes that constructing an empty string is acceptable behavior when your function returns NULL.
I don't generally advocate subclassing standard containers, but in this case it might work.
class mystring : public std::string
{
// ... appropriate constructors are an exercise left to the reader
mystring & operator=(const char * right)
{
if (right == NULL)
{
clear();
}
else
{
std::string::operator=(right); // I think this works, didn't check it...
}
return *this;
}
};
Something like this should fix your problem.
const char *cString;
std::string imacppstring;
cString = somecstylefunction();
if (cString == NULL) {
imacppstring = "";
} else {
imacppstring = cString;
}
If you want, you could stick the error checking logic in its own function. You'd have to put this code block in fewer places, then.