Standard containers encapsulation and range-based for loops - c++

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.

Related

Making a class iterable with iteration order depending on class implementation

I have a type that has two different implementations, using different data structures. One stores its data in a std::vector<std::unique_ptr<Data>>, the other in a 2D array Data***.
The elements are stored in a specific order, meaning that their position in the vector or 2D array matters. As such, when wanting to iterate over all data in my class, my for loops are dependent on the implementation, being basically one of the following:
for(auto& data : myClass->dataVector) { do Stuff }
for(int x = 0; x < myClass->xVals; x++) {
for(int y = 0; y < myClass->yVals; y++ {
do Stuff with myClass->dataArr[x][y]
}
}
Since the two version of my class share similarities, I want to have a proper parent class that is implemented by two inheriting classes, hopefully in a way that I can iterate over my data by simply doing something such as:
for(auto& data : myClass) { doStuff }
(notice how myClass acts as if it was a collection itself, even if it actually is just a container of a collection)
where the way and order in which this iteration works obviously depends on the implementation of the class.
How do make my class iterable in such a manner?
Lets assume you have a base with all the data, and two derived classes with traversal behavior:
class Base {
public:
std::vector<...> dataVector;
int xVals;
int yVals;
Data** dataArr;
};
Defining .begin() and .end() makes a class iterable with for_each. A simple forwarding to the vector iterators is enough for the first case:
class DerivedA : private Base {
public:
auto begin() { return this->dataVector.begin(); }
auto begin() const { return this->dataVector.begin(); }
auto end() { return this->dataVector.end(); }
auto end() const { return this->dataVector.end(); }
}
For the Data** case you will have to define a custom iterator:
class iterator {
public:
using value_type = Data;
using difference_type = std::ptrdiff_t;
using reference = Data&;
using pointer = Data*;
using iterator_category = std::forward_iterator_tag;
iterator() : m_base(), m_idx(0) { }
iterator(Base* b, std::size_t idx) : m_base(b), m_idx(idx) { }
reference operator*() const { return m_base->dataArr[m_idx / m_base->yVals][m_idx % m_base->y_vals]; }
pointer operator->() const { return &**this; }
friend iterator& operator++(iterator& rhs) { ++rhs.m_idx; return rhs; }
friend iterator operator++(iterator& lhs, int) { auto cp = lhs; ++lhs; return cp; }
friend bool operator==(iterator lhs, iterator rhs) { return lhs.m_idx == rhs.m_idx; }
friend bool operator!=(iterator lhs, iterator rhs) { return !(lhs == rhs); }
private:
Base* m_base;
std::size_t m_idx;
};
class const_iterator {
// equivalent but const. (reference = const Data& and pointer = const Data*)
// Make sure iterator is convertible to const_iterator.
};
class DerivedB : private Base {
iterator begin() { return { this, 0 }; }
const_iterator begin() const { return { this, 0 }; }
iterator end() { return { this, this->xVals*this->yVals }; }
const_iterator end() const { return { this, this->xVals*this->yVals }; }
};

Cannot use range-for loop for a custom type inside a template function - C++ [duplicate]

(also see Is there a good way not to hand-write all twelve required Container functions for a custom type in C++? )
For a class such as
namespace JDanielSmith {
class C
{
const size_t _size;
const std::unique_ptr<int[]> _data;
public:
C(size_t size) : _size(size), _data(new int[size]) {}
inline const int* get() const noexcept { return _data.get(); }
inline int* get() noexcept { return _data.get(); }
size_t size() const noexcept { return _size; }
};
}
what is the preferred way to expose iteration? Should I write begin()/end() (and cbegin()/cend()) member functions?
const int* cbegin() const {
return get();
}
const int* cend() const {
return cbegin() + size();
}
or should these be non-member functions?
const int* cbegin(const C& c) {
return c.get();
}
const int* cend(const C& c) {
return cbegin(c) + c.size();
}
Should begin()/end() have both const and non-const overloads?
const int* begin() const {
return get();
}
int* begin() {
return get();
}
Are there any other things to consider? Are there tools/techniques to make this "easy to get right" and reduce the amount of boiler-plate code?
Some related questions/discussion include:
Should custom containers have free begin/end functions?
Why use non-member begin and end functions in C++11?
When to use std::begin and std::end instead of container specific versions
There is a standard which describes what your class interfaces should look like if you want them to be congruent with the STL. C++ has this notion of 'concepts' which pin down the requirements for a given class to be a sufficient implementation of a concept. This almost became a language feature in c++11.
A concept you may be interested in is the Container concept. As you can see, in order to meet the requirements of the Container concept, you need begin, cbegin, end, and cend as member functions (among other things).
Since it looks like you're storing your data in an array, you might also be interested in SequenceContainer.
I'll take option C.
The main problem here is that std::begin() doesn't actually work for finding non-member begin() with ADL. So the real solution is to write your own that does:
namespace details {
using std::begin;
template <class C>
constexpr auto adl_begin(C& c) noexcept(noexcept(begin(c)))
-> decltype(begin(c))
{
return begin(c);
}
}
using details::adl_begin;
Now, it doesn't matter if you write your begin() as a member or non-member function, just use adl_begin(x) everywhere and it'll just work. As well as for both the standard containers and raw arrays. This conveniently side-steps the member vs. non-member discussion.
And yes, you should have const and non-const overloads of begin() and friends, if you want to expose const and non-const access.
I suggest creating both sets of functions -- member functions as well as non-member functions -- to allow for maximum flexibility.
namespace JDanielSmith {
class C
{
const size_t _size;
const std::unique_ptr<int[]> _data;
public:
C(size_t size) : _size(size), _data(new int[size]) {}
inline const int* get() const { return _data.get(); }
inline int* get() { return _data.get(); }
size_t size() const { return _size; }
int* begin() { return get(); }
int* end() { return get() + _size; }
const int* begin() const { return get(); }
const int* end() const { return get() + _size; }
const int* cbegin() const { return get(); }
const int* cend() const { return get() + _size; }
};
int* begin(C& c) { return c.begin(); }
int* end(C& c) { return c.end(); }
const int* begin(C const& c) { return c.begin(); }
const int* end(C const& c) { return c.end(); }
const int* cbegin(C const& c) { return c.begin(); }
const int* cend(C const& c) { return c.end(); }
}
The member functions are necessary if you want to be able to use objects of type C as arguments to std::begin, std::end, std::cbegin, and std::cend.
The non-member functions are necessary if you want to be able to use objects of type C as arguments to just begin, end, cbegin, and cend. ADL will make sure that the non-member functions will be found for such usages.
int main()
{
JDanielSmith::C c1(10);
{
// Non-const member functions are found
auto b = std::begin(c1);
auto e = std::end(c1);
for (int i = 0; b != e; ++b, ++i )
{
*b = i*10;
}
}
JDanielSmith::C const& c2 = c1;
{
// Const member functions are found
auto b = std::begin(c2);
auto e = std::end(c2);
for ( ; b != e; ++b )
{
std::cout << *b << std::endl;
}
}
{
// Non-member functions with const-objects as argument are found
auto b = begin(c2);
auto e = end(c2);
for ( ; b != e; ++b )
{
std::cout << *b << std::endl;
}
}
}
In order to create a valid iterator, you must ensure that std::iterator_traits is valid. This means you must set the iterator category among other things.
An iterator should implement iterator(), iterator(iterator&&), iterator(iterator const&), operator==, operator !=, operator++, operator++(int), operator*, operator=, and operator->. It's also a good idea to add operator< and operator+ if you can (you can't always, e.g. linked lists.)
template <typename T>
class foo
{
public:
using value_type = T;
class iterator
{
public:
using value_type = foo::value_type;
using iterator_category = std::random_access_iterator_tag;
// or whatever type of iterator you have...
using pointer = value_type*;
using reference = value_type&;
using difference_type = std::ptrdiff_t;
// ...
};
class const_iterator
{
// ...
};
iterator begin() { /*...*/ }
iterator end() { /*...*/ }
const_iterator cbegin() const { /*...*/ }
const_iterator cend() const { /*...*/ }
/* ... */
};
See: http://en.cppreference.com/w/cpp/iterator/iterator_traits for more information on what you need to make a valid iterator. (Note: You also need certain properties to be a valid "container", like .size())
Ideally you should use member functions for begin and end, but it's not required... you can also overload std::begin and std::end. If you don't know how to do that, I suggest you use member functions.
You should create begin() const and end() const, but it should be an alias for cbegin(), NEVER the same as begin()!

calling begin and end on vector returned by member function

I have this class:
class foo{
public:
const std::vector<int> get_v() const{
return v_;
}
private:
std::vector<int> v_
};
Can I use it like this?
int main(){
foo f;
some_non_inplace_std_function(f.get_v().cbegin(),f.get_v().cend());
}
Will the first f.get_v() point to the same vector of the second f.get_v() ?
get_v() returns by value, so each time you call it you get a new copy of the original. That means that the begin and end iterators obtained from different calls to get_v() do not belong to the same sequence.
If you really intend to return by value, then you need to copy the result in order to use the iterator pair:
auto v = f.get_v();
some_non_inplace_std_function(v.cbegin(), v.cend());
Otherwise, you can return by reference, or return iterators or an iterator range object directly from foo.
const std::vector<int>& get_v() const{ ... }
or
struct foo{
std::vector<int>::const_iterator begin() const{ return v_.begin(); }
std::vector<int>::const_iterator end() const{ return v_.end(); }
....
private:
std::vector<int> v_
};
const std::vector<int> get_v() const{
return v_;
}
You are returning a copy of the vector v_. You may want to return reference to the v_
const std::vector<int>& get_v() const{
return v_;
}
No you making a new copy each time you are calling get_v. To solve this you could return a const reference:
const std::vector<int>& get_v() const { return v_; }
You should change to return reference like
const std::vector<int>& get_v() const {
return v_;
}

Vector containing a partial subset of another vector both pointing to the same memory

I have a matrix class that stores its data in a std::vector:
std::vector<double> mData(mRows*mCols);
The class has a method to extract a column from this matrix:
std::vector<double> matrix::getCol(const int &n) const
{
std::vector<double> Col(mRows);
for(int ii = 0; ii < mRows; ii++)
{
Col[ii] = mData[n*mRows + ii];
}
return Col;
}
I would like to have this method return a reference to a vector that is a subset of mData. Is something like this possible?
std::vector<double>& matrix::getCol(const int &n)
{
std::vector<double> Col(mRows);
&Col[0] = &mData[n*mRows];
return Col;
}
The reason that I am interested in this is that I would like to use this method in assignment:
matrix A(rows,cols);
std::vector<double> newCol(rows);
A.getCol(0) = newCol;
Another alternative is to write a array_ref class, which contains a pointer to data and size, but does not own the data. It would allow modifications to elements, but no inserts or erases. Then you could construct it to point at regular arrays, vectors, of subsets of either. This is actually a fairly common practice with strings having a string_ref class, that might refer to the contents of a std::string, or a char*, or a char[N]. It would be fairly simple, and requires virtually no changes to your existing matrix class.
//untested sample
template<class T>
struct array_ref {
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef T* iterator;
typedef const T* const_iterator;
array_ref() : data(nullptr), len(0) {}
array_ref(T* data_, size_t len_) : ptr(data_), len(len_) {}
T& at(size_t index) {assert_range(index); return ptr[index];}
const T& at(size_t index) const {assert_range(index); return ptr[index];}
T* begin() {return ptr;}
const T* begin() const {return ptr;}
T* end() {return ptr+len;}
const T* end() const {return ptr+len;}
T* data() {return ptr;}
const T* data() const {return ptr;}
T& operator[](size_t index) {return ptr[index];}
const T& operator[](size_t index) const {return ptr[index];}
size_t size() const {return len;}
private:
void assert_range(size_t index) const
{if (index>=len) throw std::out_of_range("out of range");}
T* ptr;
size_t len;
};
One way is to store the matrix's data into a std::vector<std::vector<double> >. Then, the implementation of matrix::getCol() is straightforward.
class matrix {
public:
matrix(int row, int col)
: mData(col, std::vector<double>(row))
{
}
std::vector<double>& getCol(int n)
{
return mData[n];
}
private:
std::vector<std::vector<double> > mData;
};
matrix A(rows, cols);
std::vector<double> newCol(rows);
A.getCol(0) = newCol; // works fine
Another way is defining matrix::setCol() instead.

Implement qsort() in terms of std::sort()

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.