Understanding operator overloading & iterator why does it print out "wrhrwwr"? - c++

In the following code the output is "wrhrwwr", I try to understand what the iterator is doing, also how the "++" is overloaded. It seems like it somehow skips the 'e'. However, the code is very unclear to me, maybe I can be helped.
Thank you
#include <iostream>
using namespace std;
class datas {
private:
const char *string,marker;
const int len;
public:
class hophop {
private:
const char *pos, next;
public:
char operator *() { return *pos; }
hophop operator ++() {++pos;while (*(pos+1)!=next) ++pos; return *this; }
bool operator !=(hophop &o) { return pos < o.pos; }
hophop(const char *p, char m) : pos(p),next(m) {}
};
typedef hophop iterator;
iterator begin() { return hophop (string, marker); }
itrator end () { return hophop(string +len ,marker); }
datas(const char *d,int l, char m) : string (d), len(l),marker(m){}
};
int main( void ) {
datas chars ("we are where we were", 20, 'e');
for (char c: chars)
cout << c;
return 0;
}

It will be easier to see by pulling hophop out of the datas class. Now you can see the hophop constructor and what it is up to. I would have removed the return value of the ++operator, set it to void, to point out it does nothing here.
#include <iostream>
class hophop {
private:
const char* pos, next;
public:
hophop(const char* p, char m) : pos(p), next(m) {}
char operator *() { return *pos; }
hophop operator ++() {
++pos;
while (*(pos + 1) != next)
++pos;
return *this;
}
bool operator !=(const hophop& o) { return pos < o.pos; }
};
class datas {
private:
using iterator = hophop;
const char* string, marker;
const int len;
public:
datas(const char* d, int l, char m) : string(d), len(l), marker(m) {}
iterator begin() { return hophop(string, marker); }
iterator end() { return hophop(string + len, marker); }
};
int main(void) {
datas chars("we are where we were", 20, 'e');
// w r h r w w r
for (char c : chars)
std::cout << c;
std::cout << "\nusing a non range based for loop:" << std::endl;
for (hophop it = chars.begin(); it != chars.end(); ++it)
std::cout << *it;
std::cout << "\nor where the return value could be used:" << std::endl;
auto it = chars.begin();
std::cout << *it;
for (; it != chars.end();)
std::cout << *++it;
}
So now it may be easier to see how the hophop ++ operator is working. operator *() gets called at the beginning of the loop so no matter what the first character is, it gets retrieved. Then the ++operator is called and it moves the iterator at least once forward and until it matches next. Then it returns the character before the match. Look at the comment in main. The first and every character before the e is returned.
If you have not used a debugger much, you should. by putting a break point in operator++ you can see what is happening.
UPDATE
I had previously set the return value of the ++operator to void. As #JaMiT points out, it is appropriate for the operator to return *this. I've also added two more loops, they should be clearer than using a range based loop. The third example actually uses the return value of the ++operator, the first two loops don't.
And, get in the habit of not using namespace std; It will save you from troubles down the road.

Related

how to read data from text file and store it into array in c++

I am trying to read the data from a text file and store it into array. I need it for solving FEM problem. Let's say my text file is as follows:
node: 1,2,3,4,5,6,7,8,9,10
x: 4,4,3.75,3.76773151,3,3.59192947,4,3.5,3.55115372,3.375, 3.71330586
y: 3,275,3,2.65921885,2.79192947,2.5,3,2.55115372,2.78349365,2.36222989
z: 0,0,0,0,0,0,0,0,0,0
I want to store this data from text file into a 10*4 matrix (myarray[10][4]). Also I need to store each column of this array into a vector. Let's say my vectors are:
double x[10];
double y[10];
double z[10];
for (int i = 0; i < 10; i++)
{
x[i] = myarray[i][1];
y[i] = myarray[i][2];
z[i] = myarray[i][3];
}
I wrote the code like this:
int main()
{
string line;
string coordinate[10][4];
ifstream mesh("mesh.txt");
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (getline(mesh, line, ';'))
{
coordinate[i][j] = line;
cout << coordinate[i][j] << endl;
cout << "mesh : " << line[0] << endl;
}
}
}
mesh.close();
}
Now my problem is when I want to put the each column of coordinate into a vector I get this error:
no suitable conversion function from string to double exist
I don't understand this error, and need help fixing it.
An iterative way may like this, use the splitter in a customized iterator class. It seems to be complicated but I think it's easy to maintain.
Note that the iterator class is a modified version of this great answer.
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
template <typename T>
class istream_line_iterator : public std::iterator<std::input_iterator_tag, T> {
std::istream* stream;
public:
// Creating from a stream or the end iterator.
istream_line_iterator(std::istream& s) : stream(&s) { dropLeadingSpace(); }
istream_line_iterator() : stream(nullptr) {}
// Copy
istream_line_iterator(istream_line_iterator const& copy)
: stream(copy.stream) {}
istream_line_iterator& operator=(istream_line_iterator const& copy) {
stream = copy.stream;
return *this;
}
// The only valid comparison is against the end() iterator.
// All other iterator comparisons return false.
bool operator==(istream_line_iterator const& rhs) const {
return stream == nullptr && rhs.stream == nullptr;
}
bool operator!=(istream_line_iterator const& rhs) const {
return !(*this == rhs);
}
// Geting the value modifies the stream and returns the value.
// Note: Reading from the end() iterator is undefined behavior.
T operator*() const {
T value;
(*stream) >> value;
return value;
}
T* operator->() const; // Not sure I want to implement this.
// Input streams are funny.
// Does not matter if you do a pre or post increment. The underlying stream
// has changed. So the effect is the same.
istream_line_iterator& operator++() {
dropLeadingSpace();
return *this;
}
istream_line_iterator& operator++(int) {
dropLeadingSpace();
return *this;
}
private:
void dropLeadingSpace() {
// Only called from constructor and ++ operator.
// Note calling this on end iterator is undefined behavior.
char c;
while ((*stream) >> std::noskipws >> c) {
if (c == '\n') {
// End of line. So mark the iterator as reaching end.
stream = nullptr;
return;
}
if (!std::isspace(c) && c != ',') {
// Found a non space character so put it back
stream->putback(c);
return;
}
}
// End of stream. Mark the iterator as reaching the end.
stream = nullptr;
}
};
int main() {
std::ifstream ifs("1.in");
std::string line;
std::vector<std::vector<double>> vec;
while (std::getline(ifs, line)) {
std::istringstream iss(line);
std::string pre;
iss >> pre;
std::vector<double> line_vec;
auto beg = istream_line_iterator<double>(iss);
auto end = istream_line_iterator<double>();
std::copy(beg, end, std::back_inserter(line_vec));
vec.push_back(std::move(line_vec));
}
for (const auto& inner : vec) {
for (auto d : inner) {
std::cout << d << ' ';
}
std::cout << std::endl;
}
return 0;
}

std::map<struct,struct>::find is not finding a match, but if i loop thru begin() to end() i see the match right there

struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout&o)const {
return cl < o.cl || cs < o.cs;
}
} ;
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin&o)const {
return mss < o.mss || pinid < o.pinid || tm<o.tm; //no tdi right now it's always empty
}
};
std::map <chainin,chainout> chainmap;
std::map<chainin,chainout>::iterator it;
chainin ci;
chainout co;
string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p,const string tm, const string tid,const LONG mss){
ci.tm=tm;
// ci.tdi=tid;
ci.tdi="";
ci.mss=(short)mss;
ci.pinid=p;
for (it=chainmap.begin();it!=chainmap.end();it++){
if(it->first.pinid==ci.pinid && it->first.tm==ci.tm&&it->first.mss==ci.mss && it->first.tdi==ci.tdi){
cout << "BDEBUG: found p["; cout<<it->first.pinid; cout<<"] tm["; cout<<it->first.tm.c_str();cout<<"] mss[";cout<<it->first.mss;cout<<"] : ";cout<<it->second.chainSignal.c_str();cout<<endl;
}
}
it=chainmap.find(ci);
if(it == chainmap.end()){
MSG(SEV_T,("no pin data found for pin[%ld]/tm[%s]/tdi[%s]/mss[%ld]",ci.pinid,ci.tm.c_str(),ci.tdi.c_str(),ci.mss));
}
return it->second.cs;
}
This is both printing the successfully found line, and then throwing the sev_t error due to map::find not returning a match. what did i do wrong?
I added print statements thruout the < function, but it seems to be ordering the map correctly, and when i do the lookup, it seems to find the correct mss/pinid, but then only sees one tm, which is the wrong tm.
As noted in comments, you have a bad comparison operator. If you don't know what order the objects should be sorted in, then neither does std::map or any other sorted container.
When you have multiple things to compare, consider deciding which is most important, and use std::tie to compare them, as demonstrated here:
#include <string>
#include <iostream>
struct chainout {
int cl;
std::string cs;
bool operator<(const chainout&o)const {
return std::tie(cl, cs) < std::tie(o.cl, o.cs);
}
};
int main(){
chainout a{ 1, "b" };
chainout b{ 2, "a" };
std::cout << (a < b) << std::endl;
std::cout << (b < a) << std::endl;
}
The operator< for both of your structs are implemented incorrectly.
std::map requires key comparisons to use Strict Weak Ordering. That means when your structs want to compare multiple fields, they need to compare later fields only when earlier fields compare equal. But you are not checking for that condition. You are returning true if any field in one instance compares less-than the corresponding field in the other instance, regardless of the equality (or lack of) in the other fields. So you are breaking SWO, which causes undefined behavior in std::map's lookups.
Try this instead:
struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout &o) const {
/*
if (cl < o.cl) return true;
if (cl == o.cl) return (cs < o.cs);
return false;
*/
return (cl < o.cl) || ((cl == o.cl) && (cs < o.cs));
}
};
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin &o) const {
if (mss < o.mss) return true;
if (mss == o.mss) {
if (pinid < o.pinid) return true;
if (pinid == o.pinid) return (tm < o.tm);
}
return false;
}
};
An easier way to implement this is to use std::tie() instead, which has its own operator< to handle this for you, eg:
struct chainout {
LONG cl;
std::string cs;
bool operator<(const chainout &o) const {
return std::tie(cl, cs) < std::tie(o.cl, o.cs);
}
};
struct chainin{
std::string tm;
std::string tdi;
short mss;
LONG pinid;
bool operator<(const chainin &o) const {
return std::tie(mss, pinid, tm) < std::tie(o.mss, o.pinid, o.tm);
}
};
Either way, then std::map::find() should work as expected, eg:
std::map<chainin, chainout> chainmap;
string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p, const string tm, const string tid, const LONG mss)
{
chainin ci;
ci.tm = tm;
//ci.tdi = tid;
ci.tdi = "";
ci.mss = (short) mss;
ci.pinid = p;
std::map<chainin, chainout>::iterator it = chainmap.find(ci);
if (it != chainmap.end()) {
cout << "BDEBUG: found"
<< " p[" << it->first.pinid << "]"
<< " tm[" << it->first.tm << "]"
<< " mss[" << it->first.mss << "]"
<< " : " << it->second.cs
<< endl;
}
}

character string to bitset in C++

I am still kind of new to C++ and am trying to figure out what I am not able to pass a value correctly to a bitset, at least I suspect that is what the problem is.
I wrote a small function to assist in flipping the bits of a hex value to reverse the endian. So example would be input 0x01 and it would return 0x80.
This is the code I wrote.
int flipBits(char msd, char lsd) {
char ch[5];
sprintf_s(ch, "0x%d%d", msd, lsd);
char buffer[5];
strncpy_s(buffer, ch, 4);
cout << ch << endl;
cout << buffer << endl;
bitset<8> x(buffer);
bitset<8> y;
for (int i = 0; i < 8; i++) {
y[i] = x[7 - i];
}
cout << y << endl; // print the reversed bit order
int b = y.to_ulong(); // convert the binary to int
cout << b << endl; // print the int
cout << hex << b << endl; // print the hex
return b;
}
I tried adding the strncpy because I thought maybe the null terminator from sprintf was not working properly with the bitset. If in the line
bitset<8> x(buffer);
I replace buffer with a hex value, say for example 0x01, then it works and prints out 0x80 as I would expect, but if I try to pass in the value with the buffer it doesn't work.
We can write a stl-like container wrapper such that we can write:
int main() {
std::bitset<8> x(0x01);
auto container = make_bit_range(x);
std::reverse(container.begin(), container.end());
std::cout << x << std::endl;
}
and expect the output:
10000000
full code:
#include <iostream>
#include <bitset>
#include <algorithm>
template<std::size_t N>
struct bit_reference {
bit_reference(std::bitset<N>& data, int i) : data_(data), i_(i) {}
operator bool() const { return data_[i_]; }
bit_reference& operator=(bool x) {
data_[i_] = x;
return *this;
}
std::bitset<N>& data_;
int i_;
};
template<std::size_t N>
void swap(bit_reference<N> l, bit_reference<N> r) {
auto lv = bool(l);
auto rv = bool(r);
std::swap(lv, rv);
l = lv;
r = rv;
}
template<std::size_t N>
struct bit_range {
using bitset_type = std::bitset<N>;
bit_range(bitset_type &data) : data_(data) {}
struct iterator {
using iterator_category = std::bidirectional_iterator_tag;
using value_type = bit_reference<N>;
using difference_type = int;
using pointer = value_type *;
using reference = value_type &;
iterator(bitset_type &data, int i) : data_(data), i_(i) {}
bool operator==(iterator const &r) const { return i_ == r.i_; }
bool operator!=(iterator const &r) const { return i_ != r.i_; }
iterator &operator--() {
return update(i_ - 1);
}
iterator &operator++() {
return update(i_ + 1);
}
value_type operator*() const {
return bit_reference<N>(data_, i_);
}
private:
auto update(int pos) -> iterator & {
i_ = pos;
return *this;
}
private:
bitset_type &data_;
int i_;
};
auto begin() const { return iterator(data_, 0); }
auto end() const { return iterator(data_, int(data_.size())); }
private:
bitset_type &data_;
};
template<std::size_t N>
auto make_bit_range(std::bitset<N> &data) {
return bit_range<N>(data);
}
int main() {
std::bitset<8> x(0x01);
auto container = make_bit_range(x);
std::reverse(container.begin(), container.end());
std::cout << x << std::endl;
}
also plenty of fun algorithms here: Best Algorithm for Bit Reversal ( from MSB->LSB to LSB->MSB) in C

Comparing function of binary_search

I am trying to run binary_search on vector of custom objects.
struct T{
string name;
T(string n):name(n){};
bool operator < ( T * n ) const {
return name < n -> name;
}
bool operator == ( T * n ) const {
return name == n -> name;
}
};
vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
bool has_3 = binary_search( t.begin(), t.end(), new T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
The comparation function should be just fine yet when i run the code has_3 equals to 0 = the element isnt present in vector. Is this problem caused by my overloading of < ? I see no reason why this shouldnt find the value. Considering the order of insertion into vector it should be sorted
Thanks for help.
There are several reasons why this shouldn't find the value:
The range must be sorted; your range is out of alphabetical order
Your comparison functionality is defined between T and T*, while you search a vector of T* for a T*.
You can fix the first problem by swapping "two" and "three", and the second problem by making a vector of T:
struct T{
string name;
T(string n):name(n){};
bool operator < ( const T &n ) const {
return name < n.name;
}
// operator == is not necessary for binary_search
};
int main() {
vector<T> t;
t.push_back(T("one"));
t.push_back(T("three"));
t.push_back(T("two"));
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
return 0;
}
Demo 1.
If you do have no way but to construct a vector of pointers, you have this ugly work-around available (I strongly recommend against it):
struct T{
string name;
T(string n):name(n){};
};
bool operator < (const T& l, const T *r) {
return l.name < r->name;
}
bool operator < (const T *l, const T &r) {
return l->name < r.name;
}
Now you can search like this:
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
Demo 2.
It's a really dumb requirement to work with a vector of pointers to dynamically allocated objects. But here is an approach that will work.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
};
// this is the comparater needed to work with pointers, but it should
// NOT be a member of T
bool pointer_comparer(const T *left, const T *right)
{
// this assumes both left and right point to valid objects
return left->name < right->name;
}
int main()
{
std::vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end(), pointer_comparer);
T *value_needed = new T("two");
bool has_3 = std::binary_search( t.begin(), t.end(), value_needed, pointer_comparer);
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// since we've been stupidly allocating objects, we need to release them
delete value_needed;
for (std::vector<T *>::iterator i = t.begin(), end = t.end();
i != end; ++i)
{
delete (*i);
}
// and since t now contains a set of dangling pointers, we need to discard them too
t.resize(0);
return 0;
}
Why do I say the requirement to work with a vector of pointers to dynamically allocated objects. Compare the above with an approach that works with a vector<T> rather than a vector<T *>.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
bool operator < (const T &) const
{
return name < n.name;
};
};
int main()
{
std::vector<T> t;
t.push_back(T("one"));
t.push_back(T("two"));
t.push_back(T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end());
bool has_3 = std::binary_search(t.begin(), t.end(), T("two"));
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// we need do nothing here. All objects use above will be properly released
return 0;
}
Note: I've written the above so it works with ALL C++ standards. Assuming C++11 and later, simplifications are possible in both cases.

Error returning a list of user-defined objects from a function in C++

Background
I have written a class Str that mimics string operations, for instructional purposes. The class Str is an array of characters in essence.
I created a function makeList that receives a Str object, creates a list of Str objects using push_back and returns the list.
I am using allocators, but I have tightened the memory management to allocate only enough memory for the characters created.
Problem
Compilation, linking, and run-time produce no errors.
The list object content is OK when viewed within MakeList using cout << ret.back().
The problem is that the objects within the list have garbage input overwriting the first ~10 characters when viewed in the main body.
I have also verified that the Str I create are being destroyed via the default destructor.
I have included the minimum amount of code to replicate the problem.
Non-class code:
list<Str> makeList(const Str s)
{
list<Str> ret;
ret.push_back(s);
cout << ret.back() << endl;
return ret;
}
int main() {
Str greeting = "Hello world";
list<Str> result;
result = makeList(greeting);
result.pop_front();
cout << "The result is " << result.front() << endl;
return 0;
}
Class code:
class Str {
friend std::istream& operator>>(istream&, Str&);
public:
typedef char* iterator;
typedef const char* const_iterator;
typedef size_t size_type;
typedef char value_type;
Str() { create(); } // default constructor
Str(const_iterator cp, const_iterator cp2) {
create(cp, cp2);
}
Str(const_iterator cp) {
create(cp, cp + strlen(cp));
}
~Str() {uncreate(); }
char& operator[](size_type i) { return data[i]; }
const char& operator[](size_type i) const { return data[i]; }
Str& operator=(const Str& s) {
uncreate();
create(s.begin(), s.end());
};
Str substr(size_type i, size_type d) const {
const_iterator cStart, cTerm;
cStart = this->begin() + i;
cTerm = this->begin() + i + d;
Str sub(cStart, cTerm);
cout << "Pointer diff = " << sub.limit - sub.data << endl;
return sub;
}
size_type size() const { return avail - data; }
iterator begin() { return data; }
const_iterator begin() const { return data; }
iterator end() { return avail; }
const_iterator end() const { return avail; }
private:
iterator data;
iterator avail;
iterator limit;
allocator<char> alloc;
void create();
void create(const_iterator, const_iterator);
void uncreate();
};
void Str::create()
{
data = avail = limit = 0;
}
void Str::create(const_iterator i, const_iterator j)
{
data = alloc.allocate(j - i);
limit = avail = uninitialized_copy(i, j, data);
}
void Str::uncreate()
{
if (data) {
iterator it = avail;
while (it != data)
alloc.destroy(--it);
alloc.deallocate(data, limit - data);
}
data = limit = avail = 0;
cout << "UNCREATED" << endl;
}
ostream& operator<<(ostream& os, const Str& s) {
for (Str::size_type i = 0; i != s.size(); i++)
os << s[i];
return os;
}
Among other things, you are missing a copy constructor for Str, but you do call it here :
result2 = makeList(greeting); // Pass by value -> copy
And here :
ret.push_back(s); // Pass by value -> copy
Without it, the default copy constructor is used, but it's not doing what you want.
Possible implementation :
Str(const Str& other)
{
create(other.begin(), other.end());
}
Always respect the rule of three