I want to create a rapidjson::Value from a JSON string, e.g., [1,2,3]. Note: this is not a complete JSON object, it's just a JSON array. In Java I can use objectMapper.readTree("[1,2,3]")to create a JsonNode from a String.
My complete C++ code is as the following:
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <iostream>
// just for debug
static void print_json_value(const rapidjson::Value &value) {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
value.Accept(writer);
std::cout << buffer.GetString() << std::endl;
}
//TODO: this function probably has a problem
static rapidjson::Value str_to_json(const char* json) {
rapidjson::Document document;
document.Parse(json);
return std::move(document.Move());
}
int main(int argc, char* argv[]) {
const char* json_text = "[1,2,3]";
// copy the code of str_to_json() here
rapidjson::Document document;
document.Parse(json_text);
print_json_value(document); // works
const rapidjson::Value json_value = str_to_json(json_text);
assert(json_value.IsArray());
print_json_value(json_value); // Assertion failed here
return 0;
}
Could anyone find out the problem in my function str_to_json() ?
PS: The code above works in GCC 5.1.0 but not in Visual Studio Community 2015.
UPDATE:
According to the suggestion of #Milo Yip, the correct code is as the following:
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <iostream>
static void print_json_value(const rapidjson::Value &value) {
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
value.Accept(writer);
std::cout << buffer.GetString() << std::endl;
}
static rapidjson::Document str_to_json(const char* json) {
rapidjson::Document document;
document.Parse(json);
return std::move(document);
}
int main(int argc, char* argv[]) {
const char* json_text = "[1,2,3]";
// copy the code of str_to_json() here
rapidjson::Document document;
document.Parse(json_text);
print_json_value(document); // works
const rapidjson::Document json_value = str_to_json(json_text);
assert(json_value.IsArray());
print_json_value(json_value); // Now works
return 0;
}
Simple answer: the return type should be rapidjson::Document instead of rapidjson::Value.
Longer version: A Document contains an allocator to store all the values during parsing. When returning the Value (actually the root of the tree), the local Document object will be destructed and the buffers in the allocator will be released. It is like std::string s = ...; return s.c_str(); inside a function.
Related
A simple tcp client using ASIO causes abort() to be called for Debug builds. The same application in Release build works without throwing an error. The compiler is Visual Studio 2017.
Attaching a debugger to the application does not provide any additional information.
A demonstration example that takes the port as a command line argument that connects to server and disconnects immediately is shown below.
Any way I can avoid this error in the debug build?
#include <memory>
#include <string>
#include <iostream>
#include "asio.hpp"
using asio::ip::tcp;
class Client {
std::unique_ptr<asio::io_service> io_service_ = nullptr;
std::unique_ptr<tcp::socket> sock_ = nullptr;
public:
Client() {
io_service_ = std::make_unique<asio::io_service>();
sock_ = std::make_unique<tcp::socket>(*io_service_);
}
void connect(std::string hostname, unsigned int port) {
auto resolver = tcp::resolver(*io_service_);
auto query = tcp::resolver::query(hostname, std::to_string(port));
auto endpoint_iter = resolver.resolve(query);
asio::connect(*sock_, endpoint_iter);
}
};
int main(int argc, char* argv[]) {
try {
auto port = std::stoi(argv[1]);
Client client;
client.connect("localhost", port);
} catch (std::exception& e) {
std::cout << "\n" << e.what();
}
}
The common source of these are debug iterators. They're your friend, because they warn you about Undefined Behaviour in your program.
In this program, I see no such issues:
#include <iostream>
#include <memory>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class Client {
std::unique_ptr<boost::asio::io_service> io_service_ = nullptr;
std::unique_ptr<tcp::socket> sock_ = nullptr;
public:
Client() {
io_service_ = std::make_unique<boost::asio::io_service>();
sock_ = std::make_unique<tcp::socket>(*io_service_);
}
void connect(std::string hostname, unsigned int port) {
auto resolver = tcp::resolver(*io_service_);
auto query = tcp::resolver::query(hostname, std::to_string(port));
auto endpoint_iter = resolver.resolve(query);
boost::asio::connect(*sock_, endpoint_iter);
}
};
int main() {
try {
Client client;
client.connect("localhost", 6767);
} catch (std::exception &e) {
std::cout << "\n" << e.what();
}
}
The chief difference is that I'm not using argv[1]. Since you didn't check argc, did you in fact pass arguments for the Debug configuration?
I have a BSTR*. how to get the value from the BSTR* to std::string so that I can print it to console?
BSTR* ptr;
HRESULT result = objPtr->GetValue(ptr);
//need to print to console the value
There are many ways to pull this off; here's a simple example making use of the _bstr_t Class to effect the conversion from BSTR* to std::string.
#include "stdafx.h"
#include <Windows.h>
#include <comutil.h>
#include <iostream>
#include <string>
#pragma comment(lib,"comsuppw.lib")
int _tmain(int argc, _TCHAR* argv[])
{
const BSTR* const pbstr = new BSTR(::SysAllocString(L"Hello World"));
if (pbstr)
{
const std::string stdstr(_bstr_t(*pbstr, true));
std::cout << stdstr << std::endl;
::SysFreeString(*pbstr);
delete pbstr;
}
return 0;
}
std::wcout << ptr;
should work because it is compatible to an wchar_t*.
You can also construct a std::wstring of an BSTR that is no nullptr.
If you wish to create a std::string of it you can check outher questions like
this one but be aware of the ideas of encoding. BSTR is encoded as UTF-16.
I'm trying to use Boost library in my C++ Windows Form Application and I always get an exception:
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I'm using Visual Studio 2012 and Boost version 1.57.0. Previously I used Boost version 1.56.0 but upgrading didn't solve my issue.
Here are the code:
MyForm.cpp
#include "MyForm.h"
using namespace System;
using namespace System::Windows::Forms;
[STAThread]
void main(cli::array<String^>^ args) {
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
TestUnmanaged::MyForm form;
Application::Run(%form);
}
MyForm.h
#pragma once
#include <iostream>
#include <map>
#include <sstream>
#include <cassert>
#include <stdio.h>
#include "ExternalProfileManager.h"
#define DEFAULT_PROFILE_NAME "profile.bin"
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "lib/edk.lib")
namespace TestUnmanaged {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
ExternalProfileManager profileManager;
/// <summary>
/// Summary for MyForm
/// </summary>
public ref class MyForm : public System::Windows::Forms::Form
{
public:
MyForm(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
profileManager.load(DEFAULT_PROFILE_NAME);
std::vector<std::string> profileList;
profileManager.listProfile(profileList);
}
ExternalProfileManager.h
#ifndef EXTERNAL_PROFILE_MANAGER_H
#define EXTERNAL_PROFILE_MANAGER_H
#include <boost/serialization/string.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/tracking.hpp>
#include <boost/serialization/base_object.hpp>
class ExternalProfileManager
{
ExternalProfileManager(const ExternalProfileManager&) {};
ExternalProfileManager& operator = (const ExternalProfileManager&) {};
protected:
std::map<std::string, std::string > _profiles;
typedef std::map<std::string, std::string >::iterator profileItr_t;
// Boost serialization support
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int /*file version */)
{
ar & _profiles;
}
public:
ExternalProfileManager();
virtual ~ExternalProfileManager();
virtual bool save(const std::string& location);
virtual bool load(const std::string& location);
virtual bool insertProfile(const std::string& name, const unsigned char* profileBuf, unsigned int bufSize);
virtual bool listProfile(std::vector<std::string>& profiles);
};
//BOOST_CLASS_EXPORT(ExternalProfileManager);
//BOOST_CLASS_TRACKING(ExternalProfileManager, boost::serialization::track_never);
#endif // EXTERNAL_PROFILE_MANAGER_H
ExternalProfileManager.cpp
#include <fstream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/regex.hpp>
#pragma warning(push)
#pragma warning(disable : 4267) // "conversion from size_t to unsigned int"
#pragma warning(disable : 4996)
#include <boost/archive/archive_exception.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#pragma warning(pop)
#include "ExternalProfileManager.h"
using namespace std;
namespace fs = boost::filesystem;
ExternalProfileManager::ExternalProfileManager()
{
}
ExternalProfileManager::~ExternalProfileManager()
{
}
bool ExternalProfileManager::save(const string& location)
{
ofstream ofs(location.c_str(), ios_base::binary);
if ( !ofs.is_open() ) return false;
try {
boost::archive::binary_oarchive oa(ofs);
oa << *this;
}
catch (boost::archive::archive_exception& )
{
return false;
}
return true;
}
bool ExternalProfileManager::load(const string& location)
{
ifstream ifs(location.c_str(), ios_base::binary);
if ( !ifs.is_open() ) return false;
try {
boost::archive::binary_iarchive ia(ifs);
ia >> *this;
}
catch (boost::archive::archive_exception& )
{
return false;
}
return true;
}
bool ExternalProfileManager::insertProfile(const string& name, const unsigned char* profileBuf, unsigned int bufSize)
{
assert(profileBuf);
// Replace our stored bytes with the contents of the buffer passed by the caller
string bytesIn(profileBuf, profileBuf+bufSize);
_profiles[name] = bytesIn;
return true;
}
bool ExternalProfileManager::listProfile(vector<string>& profiles)
{
profiles.clear();
for ( profileItr_t itr = _profiles.begin(); itr != _profiles.end(); ++itr ) {
profiles.push_back(itr->first);
}
return true;
}
The error occurred in ia >> *this; in ExternalProfileManager::load (thrown in file basic_archive.cpp). So calling profileManager.load(DEFAULT_PROFILE_NAME); from form constructor will trigger the exception.
Calling save will also trigger the same exception but other functions which have no this will work fine.
I tried creating a console application in VS 2012 and call ExternalProfileManager.h and it works perfectly (including save, load, and any other function). Here are the simple console application I created to test it:
Console.cpp
#include <iostream>
#include <map>
#include <sstream>
#include <cassert>
#include <stdio.h>
#include "ExternalProfileManager.h"
#define DEFAULT_PROFILE_NAME "profile.bin"
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "lib/edk.lib")
ExternalProfileManager profileManager;
int main(int argc, char** argv) {
profileManager.load(DEFAULT_PROFILE_NAME);
std::vector<std::string> profileList;
profileManager.listProfile(profileList);
std::cout << "Available profiles:" << std::endl;
for (size_t i=0; i < profileList.size(); i++) {
std::cout << i+1 << ". " << profileList.at(i);
if (i+1 < profileList.size()) {
std::cout << std::endl;
}
}
return true;
}
profile.bin is generated from calling save function in console application and contain serialized data generated by boost. I can provide the file if it is needed to solve this issue.
I have also tried to create a simple class wrapper but the exception still occurred.
WrapperExternalProfileManager.h
#ifndef WRAPPER_EXTERNAL_PROFILE_MANAGER_H
#define WRAPPER_EXTERNAL_PROFILE_MANAGER_H
#include <string>
#include <vector>
class WrapperExternalProfileManager
{
WrapperExternalProfileManager(const WrapperExternalProfileManager&) {};
WrapperExternalProfileManager& operator = (const WrapperExternalProfileManager&) {};
public:
WrapperExternalProfileManager();
virtual ~WrapperExternalProfileManager();
virtual bool save(const std::string& location);
virtual bool load(const std::string& location);
virtual bool insertProfile(const std::string& name, const unsigned char* profileBuf, unsigned int bufSize);
virtual bool listProfile(std::vector<std::string>& profiles);
};
#endif
WrapperExternalProfileManager.cpp
#include "WrapperExternalProfileManager.h"
#include "ExternalProfileManager.h"
using namespace std;
ExternalProfileManager profileManager;
WrapperExternalProfileManager::WrapperExternalProfileManager()
{
std::cout<<"Constructor WrapperExternalProfileManager"<<std::endl;
}
WrapperExternalProfileManager::~WrapperExternalProfileManager()
{
}
bool WrapperExternalProfileManager::save(const string& location)
{
return profileManager.save(location);
}
bool WrapperExternalProfileManager::load(const string& location)
{
return profileManager.load(location);
}
bool WrapperExternalProfileManager::insertProfile(const string& name, const unsigned char* profileBuf, unsigned int bufSize)
{
return profileManager.insertProfile(name, profileBuf, bufSize);
}
bool WrapperExternalProfileManager::listProfile(vector<string>& profiles)
{
return profileManager.listProfile(profiles);
}
save and load still trigger the exception but other functions work perfectly.
Here are some property of the application which might be helpful:
Linker -> System -> SubSystem: Windows (/SUBSYSTEM:WINDOWS)
General -> Common Language Runtime Support: Common Language Runtime Support (/clr)
I know I have done something incorrectly but I don't know which part. Any suggestion to solve this issue would be appreciated.
Thanks in advance
You're going to have to find the source of your Undefined Behaviour (use static analysis tools, heap checking and divide and conquer).
I've just built your code on VS2013 RTM, using a ultra-simple C# console application as the driver:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var f = new TestUnmanaged.MyForm();
f.ShowDialog();
}
}
}
This JustWorks(TM).
I created a profile.bin with 100 random profiles of varying length:
#if 1
for (int i = 0; i < 100; ++i)
{
std::vector<uint8_t> buf;
std::generate_n(back_inserter(buf), rand() % 1024, rand);
insertProfile("profile" + std::to_string(i), buf.data(), buf.size());
}
save(location);
#endif
And they are deserialized just fine.
Good luck.
Download the full project here http://downloads.sehe.nl/stackoverflow/q27032092.zip in case you want to fiddle with it (compare the details?)
I am trying to read a text file using the following code:
void function readfile(char *inputfile) {
istream is;
int filesize = 0;
is.open(inputfile);
if (!is.is_open()) {
return;
}
is.seekg(0, ios::end);
filesize = (int)is.tellg();
is.seekg(0, ios::beg);
char *buf = new char[filesize];
is.read(buf, filesize);
is.close();
cout << buf << endl;
delete[] buf;
return;
}
While in g++ (mac / macports) it works correctly (getting all contents into a dynamic allocated char* array), in Visual Studio C++ 2010, I get constant errors of this type: Debug assertion failed: (unsigned)(c+1) <= 256, file isctype.c.
The problem is that it opens the file but can't find a termination delimeter so when it reaches the eof it starts reading somewhere else (garbage characters). Using the cout << buf; I can see that the file is being read correctly in mac but in visual c++ it types more garbage chars. What is the problem here?
Make your buffer one larger and add the terminating nul yourself.
Let C++ standard library do the work for you:
void readfile(const char *inputfile) {
std::ifstream is(inputfile);
std::string buf(std::istreambuf_iterator<char>(is), {});
std::cout << buf << std::endl;
}
See, it's now also
exception safe
handles embedded NUL characters correctly
Note, of course you can use vector instead of string if you prefer (just change that one word)
Full demo: see it live on Coliru
#include <fstream>
#include <iostream>
#include <iterator>
void readfile(const char *inputfile) {
std::ifstream is(inputfile);
std::string buf(std::istreambuf_iterator<char>(is), {});
std::cout << buf << std::endl;
}
int main()
{
readfile("main.cpp");
}
Update For C++11 challenged compilers (and showing how to use a vector):
Also Live on Coliru
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
void readfile(const char *inputfile) {
std::ifstream is(inputfile);
std::istreambuf_iterator<char> f(is), l;
std::vector<char> buf(f, l);
std::cout.write(buf.data(), buf.size());
}
int main()
{
readfile("main.cpp");
}
So I am trying to use pthread libraries for Visual C++(2012) and I get this error error C4716: 'print_message' : must return a value
Here's the code
#include "stdafx.h"
#include <iostream>
#include "pthread.h"
using namespace std;
void* print_message(void *)
{
cout << "Threading\n";
}
int main()
{
pthread_t t1;
pthread_create(&t1, NULL, print_message, NULL);
cout << "Hello";
void* result;
pthread_join(t1,&result);
return 0;
}
Add return NULL; to print_message. I'll bet you need to name the argument too.