Requirement for value in the C++ std::map? - c++

I declare a simple struct together with default constructor, copy constructor, assignment operator, and destructor. However, the struct does not work as a value type for std::map.
Here is the code:
#include <string.h>
#include <iostream>
#include <string>
#include <map>
class Foo;
std::ostream & operator<<(std::ostream & os, const Foo & v);
typedef unsigned char BYTE;
struct Foo {
char type_; // char to label type
size_t num_; // number of elem, useful if array
size_t total_; // total memory
BYTE * data_; // content of memory
Foo(const char * t) : type_('c'), num_(strlen(t)+1), total_(strlen(t)+1), data_(NULL) {
data_ = new BYTE[total_];
memcpy(data_, t, total_-1);
((char *)data_)[total_-1] = '\0';
}
Foo() : type_(), num_(), total_(), data_(NULL) {}
Foo(const Foo& rhs) : type_(rhs.type_), num_(rhs.num_), total_(rhs.total_), data_(NULL) {
if (total_) {
data_ = new BYTE[total_];
memcpy((char *)data_, (const char *)&rhs.data_, total_);
}
}
Foo & operator=(const Foo& rhs) {
if (&rhs != this) {
releaseData();
type_ = rhs.type_;
num_ = rhs.num_;
total_ = rhs.total_;
data_ = new BYTE[total_];
memcpy(data_, &rhs.data_, total_);
}
return *this;
}
~Foo() {
releaseData();
}
private:
void releaseData() {
delete [] data_; data_ = NULL;
}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.num_ << ", total: " << v.total_ << ", data: " << (const char *)v.data_ << ", data addr: " << (void *)v.data_ << ")";
return os;
}
int main() {
Foo c("/home/data/");
std::map<std::string, Foo> store;
store["abc"] = Foo("/home/data/");
std::cout << c << std::endl;
std::cout << store["abc"] << std::endl;
}
The code compiles on Linux with gcc 4.9.2. The first print correctly print out the string, but the second does not.
What is wrong with this piece of code?

Your calls to memcpy() in both the copy constructor and assignment operator are wrong. You are specifying &rhs.data_ as the source in both cases:
memcpy((char *)data_, (const char *)&rhs.data_, total_);
...
memcpy(data_, &rhs.data_, total_);
By using '&' in this manner, you are copying random bytes that immediately follow the data_ member in memory, NOT the bytes that data_ is pointing at.
Since data_ is already a pointer to the data being copied, you need to drop the & and just use rhs.data_ as-is (and there is no need for the type-casts):
memcpy(data_, rhs.data_, total_);
Alternatively, get rid of all this manual logic and just use std::string or std::vector instead, and let the compiler and STL handle all of the memory management and data copying for you:
struct Foo {
char type_; // char to label type
std::string data_; // content of memory
Foo(const char * t) : type_('c'), data_(t) {}
Foo() : type_() {}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.data_.length() << ", total: " << v.data_.capacity() << ", data: " << v.data_.c_str() << ", data addr: " << (void *)v.data_.data() << ")";
return os;
}
struct Foo {
char type_; // char to label type
std::vector<BYTE> data_; // content of memory
Foo(const char * t) : type_('c') { std::copy(t, t+(strlen(t)+1), std::back_inserter(data_)); }
Foo() : type_() {}
};
inline std::ostream & operator<<(std::ostream & os, const Foo & v) {
os << "(type: " << v.type_ << ", num: " << v.data_.size() << ", total: " << v.data_.capacity() << ", data: " << (const char*) &v.data_[0] << ", data addr: " << (void *)&v.data_[0] << ")";
return os;
}

Related

Creating a sticky manipulator that inserts a delimiter between each token of an output stream

I've seen examples that allow you to create a manipulator that inserts delimiters but none of those manipulators are sticky. That is, the manipulator returns a special class that inserts the delimiter, rather than modifying the output stream permanently so that it can do it on its own.
I want to be able to do this:
std::cout << sep(", ");
std::cout << "hello" << "world";
// "hello, world"
At the moment this prints "h, e, l, l, o, w, o, r, l, d" when I need it to be "hello, world". The reason I'm getting the wrong output is because I put the printing in the overflow() method and overflow() is being called for each character. I'm not sure where is the appropriate place to put it.
Sorry about it being verbose. If I knew a simpler way to write it I would. Just start from the bottom and work your way up:
#include <iostream>
#include <cstring>
// index for delimiter
int separator() {
static int idx = std::ios_base::xalloc();
return idx;
}
// index for storage of dynamically-allocated buffer
int rdbuffer() {
static int idx = std::ios_base::xalloc();
return idx;
}
struct custom_separator : std::streambuf {
public:
custom_separator(std::ostream& _stream)
: stream(_stream), buffer(_stream.rdbuf()) {}
int_type overflow(int_type c) {
// has a token been read already
if (token_read) {
char* delim = static_cast<char*>(stream.pword(separator()));
// print delim
buffer->sputn(delim, strlen(delim));
}
token_read = true;
return buffer->sputc(c);
}
private:
std::ostream& stream;
std::streambuf* buffer;
bool token_read = false;
};
// deletes the buffer and the delimiter
void cleanup(std::ios_base::event evt, std::ios_base& str, int idx) {
if (evt == std::ios_base::erase_event) {
delete static_cast<const char*>(str.pword(idx));
delete static_cast<custom_separator*>(str.pword(rdbuffer()));
}
}
std::ostream& set_separator(std::ostream& os, const char* str) {
if (!os.bad()) {
// If a separator string doesn't exist, assign os a buffer that prints one
if (!os.pword(separator())) {
auto buf = new custom_separator(os);
os.rdbuf(buf);
// this is to keep track of buf so we can delete it later
os.pword(rdbuffer()) = static_cast<void*>(buf);
os.register_callback(cleanup, separator());
}
// delete the previous separator
delete static_cast<const char*>(os.pword(separator()));
// store the new one
os.pword(separator()) = (void*)(str);
}
return os;
}
struct sep {
explicit sep(const char* _sep)
: separator(new char[strlen(_sep) + 1]) {
strcpy(separator, _sep);
}
sep(const sep&) = delete;
sep(const sep&&) = delete;
char* separator;
};
std::ostream& operator<<(std::ostream& os, const sep& manip) {
set_separator(os, manip.separator);
return os;
}
int main() {
std::cout << sep(", ");
std::cout << "hello";
std::cout << "world";
// "h, e, l, l, o, w, o, r, l, d"
}
The main issue with overflow() is that I don't know when to detect when the end of a token like "hello" has been read to know when to insert.
Try the following. Additionally, new line break processing (new line symbol) has been added so that the separator is not added during the transfer (after new line).
#include <iostream>
class MyStream
{
public:
struct Sep
{
Sep (const std::string& sep_value = ""):
m_sep(sep_value)
{
}
operator std::string()
{
return m_sep;
}
private:
std::string m_sep;
};
MyStream& operator << (const Sep& sep)
{
m_sep = sep;
m_add_sep = false;
return *this;
}
MyStream& operator << (const std::string& str)
{
if(str.find(MyStream::endl) != std::string::npos)
m_add_sep = false;
operator<< <std::string>(str);
m_add_sep = false;
return *this;
}
template <typename T>
MyStream& operator << (const T& value)
{
if(m_add_sep)
std::cout << static_cast<std::string>(m_sep);
std::cout << value;
m_add_sep = true;
return *this;
}
static const std::string endl;
private:
Sep m_sep;
bool m_add_sep = false;
};
const std::string MyStream::endl = std::string("\n");
int main()
{
MyStream stream;
stream << "hello" << "world" << MyStream::endl; // prints "helloworld"
stream << MyStream::Sep(", ");
stream << "hello" << "world" << MyStream::endl; // prints "hello, world"
stream << 1 << 2;
stream << 3 << MyStream::endl; // both lines prints "1, 2, 3"
stream << MyStream::Sep();
stream << 1 << 2 << 3 << MyStream::endl; // prints "123"
return 0;
}
Here's a possible solution. The separator is the same for all streams.
namespace alt_std
{
struct sep
{
sep(const char* s) { s_ = s; }
friend std::ostream& operator<<(std::ostream& os, const sep& sm)
{
return os;
}
inline static std::string s_{};
};
std::ostream& operator<<(std::ostream& os, const char* s)
{
return std::operator<<(os, s), std::operator<<(os, sep::s_);
}
}
int main()
{
using namespace alt_std;
std::cout << sep(" ") << "hello";
std::cout << "world" << std::endl; // "hello world\n"
std::cout << sep("") << "hel" << "lo"; // "hello"
}
If you want to do it at the stream object level, it's more difficult because stream objects don't have a custom storage space where you can store the value of the separator.
Or you could simply wrap the stream object:
template< typename OS >
struct wrapper
{
wrapper(OS& os, const char* sep) : os_{ os }, sep_{ sep } {}
template< typename T>
friend wrapper& operator<<(wrapper& os, const T& v)
{
os.os_ << v << os.sep_;
return os;
}
OS& os_;
std::string sep_;
};
int main()
{
wrapper os{ std::cout, " " };
os << "hello" << "world";
}

Saving and loading a class state from and to steam c++

I'm trying to figure out how to save and load an objects state to a binary stream. For context, we currently have this working but only a 'save-to-file' implementation. However, we want the serialization done in-memory to better interact with some parallelization libraries. I'm hoping this will be quite simple but my current implementation doesn't do much - can anybody spot what I'm doing wrong?
class ForSerializationAsBinary {
public:
ForSerializationAsBinary() = default;
explicit ForSerializationAsBinary(int number)
: number_(number) {}
std::ostringstream toBinaryStream() {
std::ostringstream out(std::ios::binary);
out.write((char *) &number_, sizeof(int));
return out;
}
static void fromBinaryStream(ForSerializationAsBinary &obj, std::ostringstream &os) {
int n;
std::istringstream is(std::ios::binary);
is.basic_ios<char>::rdbuf(os.rdbuf());
is.read((char *) &n, sizeof(int));
std::cout << "n: " << n << std::endl;
obj.number_ = n;
}
int number_;
};
TEST(Serialisation, SimpleSerialization) {
ForSerializationAsBinary serializationAsBinary(4);
auto o = serializationAsBinary.toBinaryStream();
ForSerializationAsBinary loaded;
ForSerializationAsBinary::fromBinaryStream(loaded, o);
std::cout << "loaded.number_: " << loaded.number_ << std::endl;
}
And the current output of the test
n: 0
loaded.number_: 0
Looks like I found the answer : just use a std::stringstream instead of the o or i versions:
class ForSerializationAsBinary {
public:
ForSerializationAsBinary() = default;
explicit ForSerializationAsBinary(int number)
: number_(number) {}
std::stringstream toBinaryStream() {
std::stringstream out(std::ios::binary);
out.write((const char *) &number_, sizeof(int));
return out;
}
static void fromBinaryStream(ForSerializationAsBinary &obj, std::stringstream &os) {
int n;
os.read((char *) &n, sizeof(int));
std::cout << "n: " << n << std::endl;
obj.number_ = n;
}
int number_;
};

Print All member of a struct in C++/CPP

I have below struct
struct abc
{
int a1;
char c1;
float f1;
int a2;
char c2;
float f2;
.
.
.
int aa1000;
char cc1000;
float ff1000;
} ;
all member of struct has different names. here for the sake of typing I have just denoted them as a1, a2 , c1, c2 and so on ... .
so array can't be created for members.
This struct is having more than 1 thousand members.
I want to print all of them in a single go for debugging purposes.
Stuct is very large otherwise a simple print function could have been written which will print each and every member.
But here, there many struct of this kind having more than thousand members and writing print function for each of them is not feasible.
Is there any way to dump/print all member of struct ?
Refactor direction :
#include <array>
#include <iostream>
//-----------------------------------------------------------------------------
struct xyz
{
int a{0};
char c{'x'};
float f{};
};
struct abc
{
std::array<xyz, 1000> records;
};
//-----------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os, const xyz& record)
{
os << "a = " << record.a << ", c = " << record.c << ", f = " << record.f << "\n";
return os;
}
std::ostream& operator<<(std::ostream& os, const abc& data)
{
std::size_t n{ 0 };
for (const auto& record : data.records)
{
os << "record[" << n++ << "] : ";
os << record;
}
return os;
}
//-----------------------------------------------------------------------------
int main()
{
abc data;
// data.x1 -> abc.x[0] etc...
// data.x2 -> abc.x[1] etc...
// data.x3 -> abc.x[2] etc...
std::cout << data;
}

How to print a vector of pairs that have as first and second 2 classes in c++?

I have something like this where Client and Order are classes :
std::vector<std::pair<Client,Order>> pair;
pair.push_back(std::make_pair(Client(2,"Anca"),Order(3,1)));
pair.push_back(std::make_pair(Client(16,"Maria"),Order(1,3)));
pair.push_back(std::make_pair(Client(29,"Alex"),Order(10,5)));
class Client{
private:
int dateWhenOrderWasPlaced;
std::string clientName;
public:
Client(int date,std::string name){
dateWhenOrderWasPlaced=date;
clientName=name;
}
class Order{
private:
int amountPizza;
int pizzaAge;
public:
Order(int amPizza,int agePizza){
amountPizza=amPizza;
pizzaAge=agePizza;
}
And i can't figure out how to print this.I have tried in many ways :
void print(std::vector<std::pair<Client,Order>> pair){
for(const auto& it : pair){
std::cout << "First: "<<pair[it].first<< ", Second: " << pair[it].second <<std::endl;
}
}
And this :
void print(std::vector<std::pair<Client,Order>> pair){
for(const auto& it : pair){
std::cout << "First: "<<it.first<< ", Second: " << it.second <<std::endl;
}
}
And in the both ways i have error(first-no operator[] and second,no operator <<)
Your first attempt does not work because it is the actual pair but std::pair does not have an operator[]. Your second attempt is the correct way to go, but it does not work because you have not defined operator<< for your classes.
So, simply define operator<<, eg:
class Client
{
private:
int dateWhenOrderWasPlaced;
std::string clientName;
public:
Client(int date, std::string name)
: dateWhenOrderWasPlaced(date), clientName(name)
{
}
friend std::ostream& operator<<(std::ostream &os, const Client &c)
{
// print c.dateWhenOrderWasPlaced and c.clientName to os as needed...
return os;
}
};
class Order
{
private:
int amountPizza;
int pizzaAge;
public:
Order(int amPizza, int agePizza)
: amountPizza(amPizza), pizzaAge(agePizza)
{
}
friend std::ostream& operator<<(std::ostream &os, const Order &o)
{
// print o.amountPizza and o.pizzaAge to os as needed...
return os;
}
};
void print(const std::vector<std::pair<Client,Order>> &pair)
{
for(const auto& it : pair)
{
std::cout << "First: " << it.first << ", Second: " << it.second << std::endl;
}
}

No operator << matches these operands [duplicate]

This question already has answers here:
How can I use cout << myclass
(5 answers)
Closed 4 months ago.
I've been reading questions here for an hour or two regarding this error I'm getting and most of them forgot to #include string (which I had already done), or to overload the << operator.
Here's the code in question:
void Student::getCoursesEnrolled(const vector<Course>& c)
{
for (int i = 0; i < c.size(); i++)
{
cout << c[i] << endl;
}
}
And the error I'm getting:
Error: No operator matches these operands
operand types are: std::ostream << const Course
All I'm trying to do is return the vector. I read about overloading the << operator but we haven't learned any of that in class so I'm assuming there is another way of doing it?
I appreciate your time!
All I'm trying to do is return the vector.
Not quite; you're trying to print it using cout. And cout has no idea how to print a Course object, unless you provide an overloaded operator<< to tell it how to do so:
std::ostream& operator<<(std::ostream& out, const Course& course)
{
out << course.getName(); // for example
return out;
}
See the operator overloading bible here on StackOverflow for more information.
The problem is that operator << is not overload for type Course objects of which you are trying to output in statement
cout << c[i] << endl;
You need to overload this operator or write your own function that will output an object of type Course in std::ostream
For example let assume that below is a definition of class Course
class Course
{
private:
std::string name;
unsigned int duration;
public:
Course() : duration( 0 ) {}
Course( const std::string &s, unsigned int n ) : name( s ), duration( n ) {}
std::ostream & out( std::ostream &os ) const
{
return ( os << "Course name = " << name << ", course duration = " << duration );
}
};
When you can write
std::vector<Course> v = { { "A", 1 }, { "B", 2 }, { "C", 3 } };
for ( const Course &c : v ) c.out( std::cout ) << std::endl;
Instead member function out you can overload operator <<. For example
class Course
{
private:
std::string name;
unsigned int duration;
public:
Course() : duration( 0 ) {}
Course( const std::string &s, unsigned int n ) : name( s ), duration( n ) {}
friend std::ostream & operator <<( std::ostream &os, const Course & c )
{
return ( os << "Course name = " << c.name << ", course duration = " << c.duration );
}
};
and use it as
std::vector<Course> v = { { "A", 1 }, { "B", 2 }, { "C", 3 } };
for ( const Course &c : v ) std::cout << c << std::endl;
The stream operator << is used to "output" some representation of that object. If you don't want to overload the operator yet just pick some property to output instead:
for (int i = 0; i < c.size(); i++)
{
cout << c[i].Name << endl; // assuming Name is a property of Course
}
When you DO overload the operator you just decide then what the proper representation of a Course is:
ostream& operator<< (ostream &out, Course &c)
{
out << c.Name "(" << c.Description << ")";
return out;
}
Your Course class needs to implement an operator:
class Course
{
public:
/*
* Your code here
*/
// Probably missing this:
friend std::ostream& operator << (std::ostream& os, const Course& course)
{
os << course.name(); // etc..
return os;
};
}; // eo class Course
Since you haven't yet learned to overload operator<<, what you can do instead is to print each member of your Course class. You haven't posted the definition of Course, but perhaps it's something like this:
class Course
{
public:
int get_number() { return _number; }
const std::string& get_name() { return _name; }
private:
int _number;
std::string _name;
};
then you can say:
void Student::getCoursesEnrolled(const vector<Course>& c)
{
for (int i = 0; i < c.size(); i++)
{
cout << c[i].get_number() << " "
<< c[i].get_name() << std::endl;
}
}
Your problem is this particular part:
cout << c[i]
In your case c[i] is an object of type Course as dvnrrs correctly pointed out. So either:
implement the overloaded << operator for your object OR
if your Course object is in someway a typedef to a primitive try explicitly casting it to a string type (or similar)