I recently started c++ programming. I shifted from Java.
I was building my own Iterable class template like this:
template<class T> class Iterable
{
T start,stop;
public:
explicit Iterable(T s,T e) {start=s; stop=e;;}
public:
virtual void next(T& i) =0;
public:
class iterator: public std::iterator<
std::input_iterator_tag, // iterator_category
T, // value_type
long, // difference_type
const T*, // pointer
T // reference
>{
T current;
Iterable<T>* obj;
public:
explicit iterator(T t,Iterable<T>* o) : obj(o) {current=t;}
iterator& operator++() {obj->next(current); return *this;}
iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
bool operator==(iterator other) const {return current == other.current;}
bool operator!=(iterator other) const {return !(*this == other);}
const T& operator*() const {return current;}
};
iterator begin() {return iterator(start,this);}
iterator end() {return iterator(stop,this);}
};
When i tried to use this iterator, I got different results when invoked differently:
for(auto S=SI.begin();S!=SI.end();S++)
{
cout << *S << "\n";
//cout << contains(seqs,S) << "\n";
if(!contains(seqs,*S))
seqs.push_back(*(new Sequence(*S)));
}
gave different results from:
for(Sequence S : SI)
{
cout << S << "\n";
//cout << contains(seqs,S) << "\n";
if(!contains(seqs,S))
seqs.push_back(*(new Sequence(S)));
}
even in the loop.
My SeqIter class (SI is object of this class) is as follows:
class SeqIter : public flex::Iterable<Sequence>
{
int n;
public:
SeqIter(int s) : Iterable(Sequence(copyList(0,s),s),Sequence(copyList(3,s),s)) {n=s;}
void next(Sequence& s)
{
char ch;
for(int i=0;i<n;i++)
{
ch=nextBase(s[i]);
s[i]=ch;
if(ch!=0)
break;
}
}
};
Sorry if this is too much code, but I do not know how much code is required.
Also, a brief explanation on the Sequence class:
It is a class that has an array of numbers (in this case I tried with 3), and it generates next sequences based on the first, i.e. 000, 100, 200, 300; 010,110 ...
Each digit ranges from 0-3 (both included)
I am unable to understand why both loops give different sequences (first gives 000 100 200 300 010 110 whereas second gives 000 100 200 300 000 110)
I thought both the loops were fundamentally same, and that the first was just the expansion of the second. Is that not so?
Also sequence class: (Sorry for delay, but I guess this is the problem)
class Sequence
{
int size=1;
char* bps;
public:
Sequence() {size=0;}
Sequence(int s)
{
size=s;
bps=new char[s];
}
Sequence(char* arr,int s)
{
size=s;
bps=arr;
}
Sequence(const Sequence& seq)
{
size=seq.size;
bps=new char[size];
strcpy(bps,seq.bps);
}
String toString() const {return *(new String(bps,size));}
inline char* toCharArray() {return bps;}
inline int getSize() const {return size;}
//operator overloading
public:
bool operator==(const Sequence& s2) const
{
if(s2.size!=size)
return false;
String r1=toString();
String r2=s2.toString();
return (r1==r2 || r1==r2.reverse());
}
inline bool operator!=(const Sequence& s2) const {return !operator==(s2);}
const char& operator[](int n) const
{
if(n>=size)
throw commons::IndexOutOfBoundsException(n,size);
return bps[n];
}
char& operator[](int n)
{
if(n>=size)
throw commons::IndexOutOfBoundsException(n,size);
return bps[n];
}
Sequence& operator=(const Sequence& seq)
{
size=seq.size;
bps=new char[size];
strcpy(bps,seq.bps);
}
};
Sorry everyone. Answering my own question after debugging:
In my Sequence class, I was using strcpy in copying char*, where the array did not end with a '\0'
Probably that caused the error:
I read online a bit more to find that the expansion was as follows:
for(Sequence S : seqs)
{
...
}
is equivalent to
for(auto i=SI.begin();i!=SI.end();i++)
{
Sequence S=*i;
...
}
So in the assignment, (S=*i) the data was not properly copied.
Sorry for all the trouble
fixed by removing assignment operator overload, and changing copy-constructor to:
Sequence(const Sequence& seq)
{
size=seq.size;
bps=new char[size];
for(int i=0;i<size;i++)
bps[i]=seq[i];
}
Related
I'm designing a class which has two standard vectors as members. I would like to be able to use range-based for loops on the vector elements and I came up with this solution
#include <iostream>
#include <vector>
using namespace std;
class MyClass {
public:
void addValue1(int val){data1_.push_back(val);}
void addValue2(int val){data2_.push_back(val);}
vector<int> const & data1() const {return data1_;}
vector<int> const & data2() const {return data2_;}
// ...
private:
vector<int> data1_;
vector<int> data2_;
// ...
};
void print1(MyClass const & mc) {
for (auto val : mc.data1()){
cout << val << endl;
}
}
void print2(MyClass const & mc) {
for (auto val : mc.data2()){
cout << val << endl;
}
}
int main(){
MyClass mc;
mc.addValue1(1);
mc.addValue1(2);
mc.addValue1(3);
print1(mc);
}
Clearly, the alternative of defining begin() and end() functions doesn't make sense since I have two distinct vectors.
I would like to ask the following questions:
A shortcoming of the proposed solution is that the contents of the two vectors cannot be changed (due to the const qualifier). In the case I need to modify the vector elements how can I modify the code?
EDIT: the modification should preserve encapsulation
Considering data encapsulation, do you think it is bad practice to return a (const) reference to the two vectors?
Use something like gsl::span<int> and gsl::span<const int>.
Here is a minimal one:
template<class T>
struct span {
T* b = 0; T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
span( T* s, T* f ):b(s),e(f) {}
span( T* s, std::size_t len ):span(s, s+len) {}
template<std::size_t N>
span( T(&arr)[N] ):span(arr, N) {}
// todo: ctor from containers with .data() and .size()
// useful helpers:
std::size_t size() const { return end()-begin(); }
bool empty() const { return size()==0; }
T& operator[](std::size_t i) const { return begin()[i]; }
T& front() const { return *begin(); }
T& back() const { return *(std::prev(end())); }
// I like explicit defaults of these:
span() = default;
span(span const&) = default;
span& operator=(span const&) = default;
~span() = default;
};
now you can write:
span<int const> data1() const {return {data1_.data(), data1_.size()};}
span<int const> data2() const {data2_.data(), data2_.size()};}
span<int> data1() {return {data1_.data(), data1_.size()};}
span<int> data2() {data2_.data(), data2_.size()};}
A shortcoming of the proposed solution is that the contents of the two vectors cannot be changed (due to the const qualifier). In the case I need to modify the vector elements how can I modify the code?
First of all, you should add a data1() and a data2() not-const versions that return a reference to the data1_ and data2_ members
vector<int> const & data1() const {return data1_;}
vector<int> const & data2() const {return data2_;}
vector<int> & data1() {return data1_;}
vector<int> & data2() {return data2_;}
Second: if you want modify the element in print1() (by example) you have to receive mc as not const reference
// ..........vvvvvvvvv no more const
void print1 (MyClass & mc) {
so you can change mc.
Third: in the range based loop you have to define val as reference so you can modify it modifying also the referenced value inside the vector
// ........V by reference
for ( auto & val : mc.data1() ) {
++val ; // this modify the value in the vector inside mc
cout << val << endl;
}
Considering data encapsulation, do you think it is bad practice to return a (const) reference to the two vectors?
IMHO: if the reference is const, not at all: it's a good practice because permit the safe use of the member without the need to duplicate it.
If the reference isn't const, I don't see big difference with declaring the member public.
I have a class which holds small numbers inside bigger integer variable. It works fine and fast and looks like this:
template
class Container<IntegerT>
static int bitsPerElement;
IntegerT data; // [0000] [0000] [0000] [0000] up to 128bits(or maybe more)
int size;
iterator as value_type return "reference" to container element:
Container::iterator
DataRef operator*()
DataRef
Container* parent;
int position;
But i got a problem of unavailability of std::sort, because it have no clue how to actually swap elements of this container (direct swapping of DataRefs is obviously pointless).
Is there any magic way to make std::sort work with it (actually to force it use custom swap function)?
Or is there decent alternative to std::sort which can handle this situation? (storing DataRefs in array is not considered as a solution)
Which is the fastest way to sort this data structure?
#ifndef INTSTORAGE_H
#define INTSTORAGE_H
#include <algorithm>
template<class T> class IntStorage;
template<class T>
class DataRef
{
public:
DataRef(IntStorage<T>* parent, int position) : m_parent(parent), m_position(position) {}
DataRef(DataRef&& o) = default;
DataRef(const DataRef& o) = default;
int value() const {return m_parent->value(m_position);}
void setValue(int value) {m_parent->setValue(m_position, value);}
DataRef& operator=(const DataRef& c)
{ setValue(c.value()); return *this; }
DataRef& operator=(const DataRef&& c)
{ setValue(c.value()); return *this; }
bool operator<(const DataRef& o) const
{ return value() < o.value(); }
IntStorage<T>* m_parent;
int m_position;
};
template<class T>
class IntStorage
{
template<typename> friend class IntStorage;
template<typename> friend class DataRef;
public:
void append(int value)
{
data |= (static_cast<T>(value) << (s_bitsPerItem * size));
++size;
}
void setValue(int index, T value)
{
data = ((~(s_mask << (s_bitsPerItem * index))) & data)
| (static_cast<T>(value) << (s_bitsPerItem * index));
}
T value(int i) const { return (data & s_mask << (i * s_bitsPerItem)) >> (i * s_bitsPerItem); }
class iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = int;
using value_type = DataRef<T>;
using pointer = DataRef<T>*;
using reference = DataRef<T>&;
iterator(IntStorage<T>* parent, int pos = 0) : ref(parent, pos) {}
inline bool operator==(const iterator& o) const { return ref.m_parent == o.ref.m_parent && ref.m_position == o.ref.m_position;}
inline bool operator!=(const iterator& o) const { return !operator==(o);}
inline const DataRef<T>& operator*() const { return ref;}
inline DataRef<T>& operator*() { return ref; }
inline iterator& operator++() { ++ref.m_position; return *this; }
inline iterator& operator--() { --ref.m_position; return *this; }
inline int operator-(const iterator& o) const { return ref.m_position - o.ref.m_position; }
inline iterator operator+(int diff) const { return iterator(ref.m_parent, ref.m_position + diff); }
inline iterator operator-(int diff) const { return iterator(ref.m_parent, ref.m_position - diff); }
inline bool operator<(const iterator& o) const { return ref.m_position < o.ref.m_position; }
DataRef<T> ref;
};
friend class iterator;
iterator begin() {return iterator(this, 0);}
iterator end() {return iterator(this, size);}
iterator cbegin() {return iterator(this, 0);}
iterator cend() {return iterator(this, size);}
static constexpr T s_mask = 0b111111;
static constexpr int s_bitsPerItem = 6;
int size = 0;
T data = 0;
};
#endif // INTSTORAGE_H
I'm trying to make the iterator work properly, and for the inequality i != a.end().
I get the error
no know conversion from argument 2 from 'const a3::vector<int>::iterator' to 'const a3::vector<int>&
for the friend function. I need the function to check if the iterator is not equal to vector.end() and am unsure how I would do it.
Class
#include <iostream>
using std::cout;
using std::endl;
namespace a3
{
template <typename T>
class vector
{
public:
class iterator {
public:
int index_;
vector* a_;
iterator() : index_(-1), a_(0) {}
iterator(int index, vector* a) : index_(index), a_(a) {}
iterator& operator=(const iterator& itr)
{
a_ = itr.a_;
index_ = itr.index_;
return *this;
}
iterator& next() {
index_++;
return *this;
}
iterator& operator++() {
return next();
}
int& operator*() { return (*a_)[index_]; }
};
private:
T* mem_;
int sz_;
public:
vector(int sz) : sz_(sz), b_(0, this), e_(sz, this)
{
mem_ = new T[sz];
}
~vector() { delete[] mem_; }
const T& operator[](T i) const { return mem_[i]; }
T& operator[](T i) { return mem_[i]; }
const int& get_size() const { return sz_; }
const iterator& begin() { return b_; }
const iterator& end() { return e_; }
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
{
return !(itr1.index_ == vec1.end);
}
private:
iterator b_;
iterator e_;
};
}
Main Function
#include "a3_vector.cpp"
int main(int argc, char** argv)
{
using namespace a3;
vector<int> a(10); // allocate an int array of size 10
for (int i=0; i<10; ++i) a[i] = i*2;
// a now looks as follows
//0,2,4,6,8,10,12,14,16,18
// prints the content of the array
vector<int>::iterator i;
for (i = a.begin(); i != a.end(); i.next()) {
cout << *i << endl;
}
}
This is fundamentally wrong:
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
Iterator comparisons should compare iterators. What you want are comparison operators that look like this:
friend bool operator!=(const iterator& itr1, const iterator& itr2);
friend bool operator==(const iterator& itr1, const iterator& itr2);
After all, that's what this expression is trying to do:
i != a.end()
You're trying to compare two iterators. The error is just trying to convert a.end() to a const vector<T>&, since that's the match that it found for !=. Simply fix != to take an iterator as the second argument and you'll be fine.
Say I have a Storage class:
class Storage
{
public:
const string& get() const { return m_data; }
const char& get(int ind) const { return m_data[ind]; }
const string& get(int s_ind, int e_ind) const { /* TBD */ }
private:
string m_data; ///< Data is so big that part of it is stored on disk
}
Say I have a Writer class that gets const Storage& and needs to access its data.
My question, is there a way to implement:
const string& get(int s_ind, int e_ind) const;
i.e, get const access to only a part of a string.
Notes:
get() is called countless of times and it is the bottleneck of my application. I'd like to avoid allocating new objects when accessing data.
is there a way to implement:
const string& get(int s_ind, int e_ind) const;
i.e, get const access to only a part of a string.
Definitely not.
What is often done - and may resolve your bottleneck - is to create a class that stores a const char* and size_t (or equally begin and end const char*s, or iterators but there's no reason to limit this to use for data in std::strings).
You could then create an object that "references" text inside a string, and use it until any of the events that would invalidate an iterator or reference to those characters happens - see the Standard or e.g. cppreference. It's possible to support stream output, comparisons, indexing etc. driven off the std::string hosted data.
Clearly you won't be able to pass such a class to functions that hardcode std::string type, but you could write it to have a similar interface, which should lessen pain.
Just as a taster (hasn't seen a compiler / flesh out as needed)...
class Text_Ref
{
public:
Text_Ref(const char* p, size_t n) : p_(p), n_(n) { }
// intuitive values for &text_ref[x] BUT text_ref[n] may not be nul
const char& operator[](size_t o) const { return p_[n]; }
*** OR ***
// text_ref[n] is nul BUT can't use &text_ref[x]
char operator[](size_t o) const { return o == n ? '\0' : p_[n]; }
// same design trade off as the operator[] alternatives above
char at(size_t o) const
{
if (o > n) throw std::out_of_range();
return o == n ? '\0' : p_[n];
}
bool empty() const { return n == 0; }
size_t size() const { return n; }
size_t length() const { return n; }
int compare(const char* p) const
{
do
{
if (*p != *p_)
return (int)*p_ - *p;
} while (*p);
return 0;
}
bool operator< (const char* p) const { return compare(p) < 0; }
bool operator<=(const char* p) const { return compare(p) <= 0; }
bool operator==(const char* p) const { return compare(p) == 0; }
bool operator!=(const char* p) const { return compare(p) != 0; }
bool operator>=(const char* p) const { return compare(p) >= 0; }
bool operator> (const char* p) const { return compare(p) > 0; }
private:
const char* p_;
size_t n;
};
inline std::ostream& operator<<(std::ostream& os, const Text_Ref& t)
{
return os.write(t.data(), t.size());
}
For stupid reasons, I'd like to write a function with the following signature (in which the (^) represents Apple's "blocks" extension to C++):
extern "C" my_qsort_b(void *arr, size_t nelem, size_t eltsize, int (^)(const void *, const void *));
where the function is implemented in terms of std::sort. (Note that I can't use qsort because it takes a function pointer, not a block pointer; and I can't use qsort_b because I might not have Apple's standard library. I won't accept answers that involve qsort_b.)
Is it possible to implement this function in C++ using std::sort? Or do I have to write my own quicksort implementation from scratch?
Please provide working code. The devil is in the details here; I'm not asking "How do I use std::sort?"
Doing this is harder than it seems it should be — although std::sort is clearly more powerful than qsort, the impedance mismatch between the two is sufficient to make implementing the latter in terms of the former a daunting task.
Still, it can be done. Here is a working implementation of my_qsort_b (here called block_qsort) that uses std::sort as the workhorse. The code is adapted from an implementation of qsort in terms of std::sort done as an exercise, and trivially modified to compare by invoking a block. The code is tested to compile and work with clang++ 3.3 on x86_64 Linux.
#include <algorithm>
#include <cstring>
struct Elem {
char* location;
size_t size;
bool needs_deleting;
Elem(char* location_, size_t size_):
location(location_), size(size_), needs_deleting(false) {}
Elem(const Elem& rhs): size(rhs.size) {
location = new char[size];
*this = rhs;
needs_deleting = true;
}
Elem& operator=(const Elem& rhs) {
memcpy(location, rhs.location, size);
return *this;
}
~Elem() {
if (needs_deleting)
delete[] location;
}
};
struct Iter: public std::iterator<std::random_access_iterator_tag, Elem> {
Elem elem;
Iter(char* location, size_t size): elem(location, size) {}
// Must define custom copy/assignment to avoid copying of iterators
// making copies of elem.
Iter(const Iter& rhs): elem(rhs.elem.location, rhs.elem.size) {}
Iter& operator=(const Iter& rhs) {elem.location = rhs.elem.location; return *this;}
char* adjust(ptrdiff_t offset) const {
return elem.location + ptrdiff_t(elem.size) * offset;
}
// Operations required for random iterator.
Iter operator+(ptrdiff_t diff) const {return Iter(adjust(diff), elem.size);}
Iter operator-(ptrdiff_t diff) const {return Iter(adjust(-diff), elem.size);}
ptrdiff_t operator-(const Iter& rhs) const {
return (elem.location - rhs.elem.location) / ptrdiff_t(elem.size);
}
Iter& operator++() {elem.location=adjust(1); return *this;}
Iter& operator--() {elem.location=adjust(-1); return *this;}
Iter operator++(int) {Iter old = *this; ++*this; return old;}
Iter operator--(int) {Iter old = *this; --*this; return old;}
bool operator!=(const Iter& rhs) const {return elem.location != rhs.elem.location;}
bool operator==(const Iter& rhs) const {return elem.location == rhs.elem.location;}
bool operator<(const Iter& rhs) const {return elem.location < rhs.elem.location;}
Elem& operator*() {return elem;}
};
struct Cmp_adaptor {
typedef int (^Qsort_comparator)(const void*, const void*);
Qsort_comparator cmp;
Cmp_adaptor(Qsort_comparator cmp_) : cmp(cmp_) {}
bool operator()(const Elem& a, const Elem& b) {
return cmp(a.location, b.location) < 0;
}
};
void block_qsort(void* base, size_t nmemb, size_t size,
int (^compar)(const void *, const void *))
{
Iter begin = Iter(static_cast<char*>(base), size);
std::sort(begin, begin + nmemb, Cmp_adaptor(compar));
}
If block_qsort needs to be called from C, you can declare it extern "C", since it uses no C++ features in its interface. To test the function, compile and run this additional code:
// test block_qsort
#include <iostream>
#include <cstring>
int main(int argc, char** argv)
{
// sort argv[1..argc].
block_qsort(argv + 1, argc - 1, sizeof (char*),
^int (const void* a, const void* b) {
return strcmp(*(char**) a, *(char**) b);
});
for (++argv; *argv; argv++)
std::cout << *argv << std::endl;
return 0;
}
to use std::sort, you'd have to write an iterator class and a class that wraps the block in a functor object. Implementing quicksort by yourself seems like a shorter alternative.
BTW: the block should be returning bool, not void, right?
Start with this:
struct memblockref {
void* location;
size_t size;
memblockref( void* loc, size_t s ):location(loc), size(s) {}
memblockref& operator=( memblockref const& right ) {
Assert( size == right.size );
memcpy( location, right.location, std::min( size, right.size ));
return *this;
}
private:
memblockref( memblockref const& ) = delete; // or leave unimplemented in C++03
memblockref() = delete; // or leave unimplemented in C++03
};
then use http://www.boost.org/doc/libs/1_52_0/libs/iterator/doc/iterator_facade.html to create iterators of memblockref to your memory buffer.
Then turn the block into a function pointer, or wrap it in a lambda or functor, and call std::sort, where you call your block based comparison on the location field of the left and right memblockref.
You may have to specialize swap or iter_swap as well, but maybe not.