I can't show you all the code, 'cause it is large but I can show example of the stuff that I'm trying to use. So, code is the following:
namespace TestNamespace {
struct TestBase
{
TestBase(std::string _id = "") : id(_id) {}
std::string id;
};
struct Test : public TestBase
{
Test(std::string _id = "") : TestBase(_id), b1(true), b2(true) {}
bool b1;
bool b2;
};
typedef std::list<Test> Tests;
struct SomeStatesHolder
{
SomeStatesHolder() : tests(), someAdditionalVar(true), someAdditionVar2(2222) {}
Tests tests;
bool someAdditionalVar;
int someAdditionVar2;
};
}
class WorkingClass
{
public:
WorkingClass() : m_someStatesHolder(new TestNamespace::SomeStatesHolder()) {
TestNamespace::Test t("id1");
m_someStatesHolder->tests.push_back(t);
}
TestNamespace::Tests getTests() const { return m_someStatesHolder->tests; }
bool getB1(const std::string& id) const {
const auto fnd = std::find_if(m_someStatesHolder->tests.cbegin(), m_someStatesHolder->tests.cend(), [&](const TestNamespace::Test& t){
return t.id == id;
});
return (fnd == m_someStatesHolder->tests.cend()) ? true : fnd->b1;
}
bool getB2(const std::string& id) const {
const auto fnd = std::find_if(m_someStatesHolder->tests.cbegin(), m_someStatesHolder->tests.cend(), [&](const TestNamespace::Test& t){
return t.id == id;
});
return (fnd == m_someStatesHolder->tests.cend()) ? true : fnd->b2;
}
private:
TestNamespace::SomeStatesHolder *m_someStatesHolder;
};
But deep in the project in function of yet another class I have lines:
qDebug() << "\n\n\n\nTESTS: "
<< workingClass.getB1("id1") << ":" << !workingClass.getB1("id1") << " "
<< workingClass.getB2("id1") << ":" << !workingClass.getB2("id1");
const auto tests = workingClass.getTests();
const std::string fid = "id1";
const auto fnd = std::find_if(tests.cbegin(), tests.cend(), [&](const TestNamespace::Test& t){
return t.id == fid;
});
qDebug() << "\nTESTS2: "
<< fnd->b1 << ":" << !fnd->b1 << " "
<< fnd->b2 << ":" << !fnd->b2;
And the output of that lines is:
TESTS: true : true true : true
TESTS2: true : true true : true
What could be the reason of such a strange behaviour? Why ! didn't work? I should admit, that
this stranges are in Linux, OSX. In Windows everything is fine
new similar test stuff works fine (like this), but my particular struct in project - not.
UPD1: I also tried to make functions for getting those values, result the same. Code like this also not working:
qDebug() << "Test3: "
<< workingClass.getB1("id1") << ":"
<< !((bool)workingClass.getB1("id1")) << ":"
<< !workingClass.getB1("id1") << ":"
<< (!(workingClass.getB1("id1")))
bool AAAAA = workingClass.getB1("id1");
qDebug() << "Test4: "
<< AAAAA << ":"
<< !((bool)AAAAA)) << ":"
<< !AAAAA << ":"
<< (!(AAAAA))
std::find_if will return last if nothing is found, which points after the last element std::list. That is memory garbage, that you are returning with return fnd->b1.
When you negate this memory garbage, the last bit will be negated, thus you end up with 112 : 113 58 : 59 when casting it to int.
I found a problem. In my project in a same class (SomeStatesHolder) my bool values wasn't initialized in constructor list.
ps: use damn -Wreorder or even better -Werror -Wall
Related
I switched from c to c++ recently and just can't figure out what I'm doing wrong here.
I would like to access and set the member of a map via another function.
Here is my example which you can just copy to cpp.sh or so if you like
#include <iostream>
#include <map>
using namespace std;
struct test{
int i;
int j;
};
void addValues(test* val){
if (val == NULL){
val = new test();
cout<<"new";
}
val->i = 10;
val->j = 12;
}
void printVal(test* val){
cout<<"finish " << val->i << " " << val->j;
}
int main()
{
map<string, test*> bla = {{"test1",NULL}};
addValues(bla.at("test1"));
printVal(bla.at("test1"));
return 0;
}
code from my project is a little bit more complex but it's basically this problem. I created a test in addValues() and have not deleted it. Why am I not able to print this value in printVal()? What am I missing?
Thanks in advance!
Parameters are passed by value. Pointers are no exception to that. Your addValues modifies a local copy of the pointer when a nullptr is passed. Modifying that local copy does not affect the pointer in the map. Pass the pointer by reference:
void addValues(test*& val){
if (val == nullptr){
val = new test();
cout<<"new";
}
val->i = 10;
val->j = 12;
}
Or better yet, do not use raw pointers in the first place. Moreover, consider to write a constructor that initializes the members of test instead of relying on the caller to initialize them.
Example :
#include <iostream>
#include <map>
//using namespace std; NO teach yourself not to do this.
struct test
{
int i = 0; // <== in c++ you can initialize values of structs
int j = 0;
};
// this instead of printVal
std::ostream& operator<<(std::ostream& os, const test& t)
{
os << "i = " << t.i << ", j = " << t.j << "\n";
return os;
}
int main()
{
std::map<std::string, test> map =
{
{"test1",{1,1}},
{"test2",{2,2}},
};
// loop over all entries in the map
// range based for loop.
// each entry in the map is a key,value pair (not they key, not the value but a pair)
// https://en.cppreference.com/w/cpp/language/range-for
std::cout << "range based for over keyvalue pairs\n";
for (const auto& kv : map)
{
// note kv.second is where we use operator<< from earlier.
std::cout << "Key : " << kv.first << ", value : " << kv.second << "\n";
}
std::cout << "\n";
// structured bindings make code more readable
// https://en.cppreference.com/w/cpp/language/structured_binding
std::cout << "range based for using structured bindings \n";
for (const auto& [key, value] : map)
{
std::cout << "Key : " << key << ", value : " << value <<"\n";
}
std::cout << "\n";
return 0;
}
#include <iostream>
using namespace std;
template<class KeyT, class ValueT>
struct KeyValuePair {
const KeyT &key_;
const ValueT &value_;
KeyValuePair() {
cout << "KeyValuePair() constructor" << endl;
}
KeyValuePair( const KeyValuePair<KeyT, ValueT> &other) {
cout << "KeyvaluePiar copy constructor" << endl;
}
KeyValuePair(KeyT key, ValueT value) : key_(key), value_(value) {
cout << "KeyValuePair(KeyT, ValueT) constructor" << " key_: " << key_ << " value_ " << value_ << endl;
}
~KeyValuePair() {}
};
struct foo {
int i;
};
void dump(const KeyValuePair<int, foo*> &kp) {
//printf("dump printf key: %d, value: %p\n", kp.key_, kp.value_);
cout << "dump cout key_: " << kp.key_ << " value_: " << kp.value_ << " i: " << (kp.value_)->i << "\n";
}
int main() {
cout << "test kv\n";
foo *ptr = new foo();
ptr->i = 3000;
printf("address of ptr: %p\n", ptr);
dump(KeyValuePair<int, foo*>(10, ptr));
return 0;
}
Run it with
g++ -g -std=c++11 -fPIC -O0 -o main main.cc && ./main
on a Linux machine.
In the above c++ example code gives the following result
test kv
address of ptr: 0x18a1010
KeyValuePair(KeyT, ValueT) constructor key_: 10 value_ 0x18a1010
dump cout key_: 10 value_: 0x7fffae060070 i: -1375338428
It seems that KeyValuePair's value_ is messed up after calling dump function, anyone knows the reason? It seems to be related to reference and pointers.
Your member variable is a reference:
const KeyT &key_;
Your constructor, on the other hand, passes by value:
KeyValuePair(KeyT key, ValueT value)
That means you are storing a reference to a temporary variable that will get destroyed almost immediately.
One solution would be to pass by reference in your constructor:
KeyValuePair(KeyT& key, ValueT& value)
which is better, but not perfect, since you pass a int literal 10 into the function.
If you really just need a pair, the best solution is probably to use std::pair.
I am writing a C++ interface for a line based protocol. The commands are simple, they are structured like this:
<cmd> <args>\n
Some commands have a fixed number of arguments, some have variable ones. I am using ostringstream to assemble the line. I wrote two base classes to cover the commands with and without variable arguments:
class format_command
{
public:
explicit format_command(std::string const &p_cmd_name)
{
m_sstream << p_cmd_name;
}
std::string get_string() const;
protected:
std::ostringstream m_sstream;
};
class format_command_with_args
: public format_command
{
public:
explicit format_command_with_args(std::string const &p_cmd_name)
{
m_sstream << p_cmd_name;
}
template < typename T >
format_command_with_args& operator << (T const &p_value)
{
m_sstream << " " << p_value;
return *this;
}
};
Individual command line generators are then derived as needed. Let's take two example commands, foo and bar. foo takes a fixed number of arguments, bar variable ones.
class format_foo
: public format_command
{
public:
explicit format_foo(std::string const &p_string, int const p_number)
: format_command("foo")
{
m_sstream << " " << p_string << " " << p_number;
}
};
class format_bar
: public format_command_with_args
{
public:
explicit format_bar(float const p_decimal, char const p_char)
: format_command("bar")
{
m_sstream << " " << p_decimal << " " << p_char;
}
};
And then I have functions that create instances of these classes.
namespace command
{
format_foo foo(std::string const &p_string, int const p_number)
{
return format_foo(p_string, p_number);
}
format_bar bar(float const p_decimal, char const p_char)
{
return format_foo(p_decimal, p_char);
}
}
I can then do this:
std::string command_str = command::foo("hello", 11).get_string();
std::string command_str = (command::bar(1.2f, 'x') << "extra-arg" << "another-arg").get_string();
I added this indirection through the command:: functions because some commands are like this:
somecmd <arg1> <arg2> [<arg3> [<varargs>]]
meaning that they have variable arguments only if a specific argument is present. So, if the third argument isn't present, I want to make sure that the user cannot add extra variable arguments with the stream operator. In such cases, I can then do this:
class format_somecmd
: public format_command
{
public:
explicit format_somecmd(std::string const &p_arg1, std::string const &p_arg2)
: format_somecmd("bar")
{
m_sstream << " " << p_arg1 << " " << p_arg2;
}
};
class format_somecmd_with_args
: public format_command_with_args
{
public:
explicit format_somecmd_with_args(std::string const &p_arg1, std::string const &p_arg2, std::string const &p_arg3)
: format_somecmd("bar")
{
m_sstream << " " << p_arg1 << " " << p_arg2 << " " << p_arg3;
}
};
namespace command
{
format_somecmd somecmd(std::string const &p_arg1, std::string const &p_arg2)
{
return format_somecmd(p_arg1, p_arg2);
}
format_somecmd_with_args somecmd(std::string const &p_arg1, std::string const &p_arg2, std::string const &p_arg3)
{
return format_somecmd_with_args(p_arg1, p_arg2, p_arg3);
}
This way, I can do this:
std::string command_str = command::somecmd("hello", "world").get_string();
std::string command_str = (command::somecmd("hello", "world", "test") << "extra-arg" << "another-arg").get_string();
and this fails at compile time (which is intentional since it would be an invalid command):
std::string command_str = (command::somecmd("hello", "world") << "extra-arg" << "another-arg").get_string();
This works well so far. The part that bothers me though is the .get_string(). I have considered using operator std::string(), but this seems like a can of worms.
Any suggestions on how to improve it, particularly with regards to get_string() ?
I want to share structured data between C++ and Python languages using MessagePack like this one:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ],
"x" : [ x0,..,xN],
"P" : [ [P00, ..., P0N], ..., [PM0,...,PMN] ]
}
The number of variables is optional so in some cases I will have for example only:
{
"t" : [ [t00,...,t0N], ... , [tM0,...,tMN] ]
}
Decoding this in Python is pretty simple, my problem is to figure out
how to decode this in C++ if I don't know in advance the structure of
the data ? or the exact number of variables that I would have; is it
possible to iterate the structure in these cases?
I managed to handle a "fixed" data structure ( always with the same
number of variables ) defining a struct for example:
struct variables
{
std::vector< std::vector<double> > t;
std::vector< double > x;
std::vector< std::vector<double> > P;
MSPACK_DEFINE_MAP( t, x, P );
};
std::stringstream inBuffer;
.... (read data )
std::string str( inBuffer.str() );
msgpack::object_handle oh = msgpack::unpack( str.data(), str.size() );
msgpack::object deserialized = oh.get();
variables var;
deserialized.convert( var );
Is there a better way to accomplish this ?, how could manage optional
variables that could not appear in the structure ?; I repeat the
previous question: could I iterate an unknown data structure in C++?,
how ?
Thanks in advance!
Regards, Ernesto
There are two ways to treat unknown data structure.
The first way is using parse/visitor mechanism.
Here is an example:
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
// This is a simple print example visitor.
// You can do any processing in your visitor.
struct my_visitor : msgpack::null_visitor {
bool start_map_key() {
processing_map_key = true;
return true;
}
bool end_map_key() {
processing_map_key = false;
return true;
}
bool start_array(uint32_t size) {
std::cout << "array (size:" << size << ")[" << std::endl;
return true;
}
bool end_array() {
std::cout << "]" << std::endl;
return true;
}
bool visit_str(const char* v, uint32_t size) {
if (processing_map_key) {
std::cout << "map key:" << std::string(v, size) << std::endl;
}
return true;
}
bool visit_positive_integer(uint64_t v) {
std::cout << "found value:" << v << std::endl;
return true;
}
bool processing_map_key = false;
std::string indent;
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
// print data (for debug)
{
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
}
// apply visitor
{
my_visitor mv;
msgpack::parse(ss.str().data(), ss.str().size(), mv);
}
}
Running demo: https://wandbox.org/permlink/3NrR4IMDIuLTk9e9
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_visitor.
The other way is using msgpack::type::variant or `msgpack::type::variant_ref.
The former copies data, you can update it. The latter doesn't copy data. You cannot update it.
This approach requires boost. So you need to define MSGPACK_USE_BOOST. I recommend defining as a compiler option.
// Boost is required
#define MSGPACK_USE_BOOST
#include <msgpack.hpp>
#include <sstream>
#include <iostream>
struct my_visitor:boost::static_visitor<void> {
void operator()(uint64_t v) const {
std::cout << "positive insteger:" << v << std::endl;
}
// const is required for map key because std::multimap's key (first) is const.
void operator()(std::string const& v) const {
std::cout << "string:" << v << std::endl;
}
void operator()(std::vector<msgpack::type::variant>& v) const {
std::cout << "array found" << std::endl;
for (auto& e : v) {
boost::apply_visitor(*this, e);
}
}
void operator()(std::multimap<msgpack::type::variant, msgpack::type::variant>& v) const {
std::cout << "map found" << std::endl;
for (auto& e : v) {
std::cout << "key:" << std::endl;
boost::apply_visitor(*this, e.first);
std::cout << "value:" << std::endl;
boost::apply_visitor(*this, e.second);
}
}
template <typename T>
void operator()(T const&) const {
std::cout << " match others" << std::endl;
}
};
int main() {
// create test data
std::stringstream ss;
msgpack::packer<std::stringstream> pk(ss);
pk.pack_map(1);
pk.pack("t");
pk.pack_array(2);
pk.pack_array(3);
pk.pack(1);
pk.pack(2);
pk.pack(3);
pk.pack_array(3);
pk.pack(4);
pk.pack(5);
pk.pack(6);
auto oh = msgpack::unpack(ss.str().data(), ss.str().size());
std::cout << oh.get() << std::endl;
msgpack::type::variant v = oh.get().as<msgpack::type::variant>();
boost::apply_visitor(my_visitor(), v);
}
Running demo: https://wandbox.org/permlink/HQwJjfwW8rLEMi0d
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_variant
Here are exampless:
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_capitalize.cpp
https://github.com/msgpack/msgpack-c/blob/master/example/boost/msgpack_variant_mapbased.cpp
Both ways can treat unpredictable data structure. You need to do some visitor processing. If the data structure is predictable some extent, your original approach is also good way.
Actually there is a simpler way, if you are dealing with maps (like stated in the question), not arrays.
msgpack::object_handle oh = msgpack::unpack(/* some data */);
std::map<std::string,msgpack::type::variant> map = obj.convert();
This way you will get a map with all the data, no need for a visitor or boost.
I'm writing some code which handles a lot of data. When an error occures, it usually happens that the error will occur many times, so I want to report it only once. The problem I have is, that I want to have individual error messages. In C I would use a method with variadic arguments, bit of course this is not really typesafe, so I wonder how I can achieve the same in C++ with typesafe output. I know that I can stringstream and create the indvidual string, but that would mean that I have to create the full error message, even if it is discarded, because it was already printed, and stringstream is not exactly fast either.
So currently I use code like this:
std::string key = "BT:EMPTY";
if(mErrorReport.find(key) == mErrorReport.end())
{
std::cerr << "ERROR [" << Name<< "] Type is empty! " << std::endl;
mErrorReport.insert(key);
}
std::string key = "UI:"+Unitcode;
if(mErrorReport.find(key) == mErrorReport.end())
{
std::cerr << "ERROR [" << Name<< "] Room with the id " << Unitcode << " doesn't exist! " << std::endl;
mErrorReport.insert(key);
}
...
In C I would have written a variadic function like this:
void ErrorLog(const char *key, int nLogLevel, const char fmt, ...)
{
// Check if this error was already reported before.
if(mErrorLog.find(key) == mErrorLog.end())
{
fprintf(stderr, fmt, ...);
mErrorLog.insert(key);
}
}
So I wonder if there is some best practice for something like that.
Why don't you just use
void ErrorLog(const std::string& key, const std::string& name, const std::string& what)
{
if (mErrorLog.find(key) == mErrorLog.end())
{
std::cerr << "ERROR[" << name << "]" << what << std::endl;
mErrorLog.insert(key);
}
}
and call it like
ErrorLog("BT:EMPTY", Name, "Type is empty!");
ErrorLog("UI:" + Unitcode, Name, std::string("Room with the id ") + Unitcode + " doesn't exist!");
If Name doesn't change you could remove the parameter and just add it to the std::err call.
Update: Alternative solution
class ErrorLogWriter
{
public:
ErrorLogWriter(const std::string& name, const std::string& key, std::set<std::string>& log)
:m_name(name)
, m_key(key)
, m_log(log)
{}
ErrorLogWriter& operator<<(const std::string& msg)
{
if (m_log.find(m_key) == m_log.end())
{
std::cerr << "ERROR[" << m_name << "]" << msg << std::endl;
m_log.insert(m_key);
}
return *this;
}
private:
std::string m_name;
std::string m_key;
std::set<std::string>& m_log;
};
class ErrorLog
{
public:
ErrorLog(const std::string& name, std::set<std::string>& log)
:m_name(name)
,m_log(log)
{}
ErrorLogWriter operator()(const std::string& key)
{
return ErrorLogWriter(m_name, key, m_log);
}
private:
std::string m_name;
std::set<std::string>& m_log;
};
int main()
{
std::string Name = "NAME";
std::string Unitcode = "UNITCODE";
std::set<std::string> mErrorLog;
ErrorLog log(Name, mErrorLog);
log("BT:EMPTY") << "Type is empty!";
log("UI:" + Unitcode) << "Room with the id " << Unitcode << " doesn't exist!";
}