I was doing some programs on Object Oreinted Programming in C++.
Here is a brief skeleton of the situation
class coll;
class ele {
private:
int val;
coll* p;
public:
ele(int v, coll* p);
int value() const;
friend bool operator==(const ele& El1, const ele& El2);
friend bool operator<(const ele& El1, const ele& El2);
};
class coll {
private:
set<ele> data;
public:
ele* min() const {
if(size()) {
set<ele>::iterator minIt = min_element(data.begin(), data.end());
ele* ptr = &(*minIt);
return ptr;
}
return nullptr;
}
};
In the min() function, the return type has to be non-const and the function has to be const compulsorily.
I don't know why, but min_element's iterator when de-referenced is giving a const reference. Like, &(*minIt) is a const pointer. But I need a non-const pointer to return.
What can be the reason for this behavior. Thanks in advance.
Related
This is the header file for the container including a try to implement random access iterators :
using namespace std;
template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
public:
Element** data;
unsigned int curr_size;
unsigned int max_size;
int* availability_array;
explicit UniqueArray(unsigned int size);
UniqueArray(const UniqueArray& other);
~UniqueArray();
// UniqueArray& operator=(const UniqueArray&) = delete;
unsigned int insert(const Element& element);
bool getIndex(const Element& element, unsigned int& index) const;
const Element* operator[] (const Element& element) const;
bool remove(const Element& element);
unsigned int getCount() const;
unsigned int getSize() const;
class Filter {
public:
virtual bool operator() (const Element&) const = 0;
};
UniqueArray filter(const Filter& f) const;
class UniqueArrayIsFullException{};
typedef Element ua_iterator;
typedef const Element ua_const_iterator;
ua_iterator begin(){
return **data;
}
ua_const_iterator begin() const {
return **data;
}
ua_iterator end(){
return *(*data + max_size);
}
ua_const_iterator end() const {
return *(*data + max_size);
}
};
A summary of the errors I get :
error: no match for ‘operator++’
error: no match for ‘operator*’
error: no type named ‘value_type’ in ‘struct std::iterator_traits<MtmParkingLot::Vehicle>
error: no match for ‘operator!=’
error: no match for ‘operator-’
On my implementation Element gets Vehicle and all these missing operators refer to Vehicle
I'm not quite sure on how to work on these errors because for example substracting Vehicles makes no sense..
If you want an iterator to return a reference to an object when it is dereferenced, you have to define a special Iterator class to do it. With boost::indirect_iterator this is pretty simple:
#include <boost/iterator/indirect_iterator.hpp>
template <class Element, class Compare = std::equal_to<Element>>
class UniqueArray {
// ...
auto begin() {
return boost::indirect_iterator<Element**, Element>(data_);
}
auto end() {
return boost::indirect_iterator<Element**, Element>(data_ + curr_size);
}
};
Simple demo
If you want to code it yourself, the idea is:
template<class Element>
class UniqueArray {
public:
//...
class Iterator {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = Element;
using reference = Element&;
// ...
Iterator(Element** d) : data(d) { }
reference operator*() {
return **data;
}
Iterator& operator++() {
++data;
return *this;
}
friend bool operator!=(Iterator it1, Iterator it2) {
return it1.data != it2.data;
}
// ...
private:
Element** data;
};
Iterator begin() {
return Iterator(data);
}
Iterator end() {
return Iterator(data + curr_size);
}
};
Note, the full random access iterator requires implementation of many other member and non-member functions. You might want to make it a forward iterator to simplify things a little bit.
Simple demo
If you write that without the type aliases, you get definitions like
Element begin(){
return **data;
}
and use like
UniqueArray<Vehicle>::ua_iterator it = something.begin();
it++;
becomes
Vehicle it = something.begin();
it++;
which makes the cause of the errors more obvious - you're trying to apply iterator operations to your element type.
If you're fine with iteration producing Element*, the simple solution is
typedef Element** ua_iterator;
ua_iterator begin(){
return data;
}
ua_iterator end(){
return data + curr_size;
}
and similar for the const versions.
Then you could write
UniqueArray<Vehicle>::ua_iterator it = something.begin();
Vehicle* v = *it;
If you want iteration to produce Element&, you need to write an iterator class with the appropriate overloads and traits.
It's not very difficult, but it gets tedious.
Take this dummy structure:
struct foo
{
int* pI;
void bar() const
{
int* ptrToI = pI; // I want this to require 'const int*'
*ptrToI = 5; // I want this to fail
}
}__test__;
How can I design this struct to prevent me from changing the value pI points to?
You can use a custom smart pointer in order to hide the underlying pointer:
template <typename T>
struct ptr_t
{
private:
T *ptr;
public:
//Constructors and assignment operators
ptr_t(): ptr(nullptr) {}
ptr_t(T* p): ptr(p) {}
ptr_t(const ptr_t &other): ptr(other.ptr) {}
ptr_t& operator=(T* p) {this->ptr=p;return *this;}
ptr_t& operator=(const ptr_t &other) {this->ptr=other.ptr; return *this;}
//Note that the smart pointers included in the standard returns non-const pointers
//That is why you need to define a custom smart pointer, which forces the const pointer return in the const version of the operators.
const T* operator->() const {return ptr;}
T* operator->() {return ptr;}
const T& operator&() const {return *ptr;}
T& operator&() {return *ptr;}
operator const T*() const {return ptr;}
operator T*() {return ptr;}
};
struct foo2
{
ptr_t<int> pI;
void nonconst_bar()
{
int* ptrToI = pI; // Now success, since not const
*ptrToI = 5;
}
void failing_bar() const
{
//int* ptrToI = pI; // This fails
//*pI = 5; // This also fails
}
void success_bar() const
{
const int* ptrToI = pI;
//*ptrToI = 5; // This is not possible anymore
}
};
Unless you can make the member const int*, you could use inheritance to hide the member from what becomes the child class, and provide a protected function in the base class that yields a const int* pointer:
class base_foo
{
int* pI;
protected:
const int* get_pI(){return pI;}
};
struct foo : base_foo
{
int* ptrToI = get_pI(); // will fail due to attempted conversion to int*
/* and so on*/
Note also that any token containing two consecutive underscores is reserved and as such, formally, the behaviour of your program is undefined: rename __test__.
I've never worked with iterators before, and I'm having trouble designing a custom iterator for a custom container class that I wrote.
Background: Using Google Tests API, these are the two test cases that I have:
TEST(RandomArray, End) {
RandomArray r(17);
int *b = r.begin();
int *e = r.end();
EXPECT_EQ(b + 17, e);
}
TEST(RandomArray, IteratorTypedef) {
RandomArray r(7);
for (RandomArray::iterator it = r.begin(); it != r.end(); ++it) {
*it = 89;
EXPECT_EQ(89, *it);
}
}
Here's my header file and the code for the iterators:
class RandomArray
{
friend ostream& operator<<(ostream&, const RandomArray&);
public:
class iterator
{
public:
typedef iterator self_type;
typedef int* pointer;
typedef int& reference;
self_type operator++() { self_type i = *this; ptr++; return i;}
reference operator*() {return *ptr;}
bool operator!=(const self_type& rhs) {return ptr != rhs.ptr;}
private:
pointer ptr;
};
class const_iterator
{
public:
typedef const_iterator self_type;
typedef int* pointer;
typedef int& reference;
self_type operator++() { self_type i = *this; ptr++; return i;}
const reference operator*() { return *ptr; }
bool operator!=(const self_type& rhs) {return ptr != rhs.ptr;}
private:
pointer ptr;
};
RandomArray();
RandomArray(size_t);
size_t size() const;
int* begin();
iterator begin();
const int* begin() const;
const iterator begin() const;
int* end();
iterator end();
const int* end() const;
const iterator end() const;
private:
size_t capacity;
int* data;
};
The error I'm getting on begin and end is the following: Error: Cannot overload functions distinguished by return type alone.
I know you're not allowed to have the same function name and same parameters with different return types, so I'm wondering if there's a better way to do this? Am I making the iterator right? Would a template help fix this? I need begin() and end() to return both an int* and an iterator so I can pass both test cases. Is there a better way to accomplish this?
I need begin() and end() to return both an int* and an iterator so I can pass both test cases.
No, you don't. The test case expecting a pointer is wrong. Containers give you back iterators. In your case, your iterator could be a pointer, but that's an implementation detail. You definitely just want:
iterator begin();
const_iterator begin() const; // NB: const_iterator, not const iterator
And then fix your unit test to expect RandomArray::iterator instead of int*. Or, even better, auto.
Note: Your operator++() does postfix increment instead of prefix increment. Also const reference is the wrong type, that woudl be int& const, and references are inherently const. You want to change your typedef for reference to itself be int const&.
If you can't change the test case with int *b = r.begin(); (though if this is a new class, why not?) then you need to either make your iterator type be the pointer type, or be convertible to the pointer type.
In the first case, get rid of the iterator classes and write using iterator = int*; using const_iterator = int const*;.
In the second case, add conversion functions operator pointer() const { return ptr; }.
The second case is better, as this allows you to deprecate the conversion function in future. However it would be even better to fix the test case to use the iterator type.
I figured out what I was doing wrong. All I had to do was declare a typedef iterator as an int*.
Updated Code:
class MyClass
{
public:
int* begin();
const int* begin() const;
int* end();
const int* end() const;
//HERE
typedef int* iterator;
typedef const int* const_iterator;
private:
size_t capacity;
int* data;
};
Then, in the function body I changed it to this:
int* MyClass::begin()
{
return iterator(&data[0]);
}
const int* MyClass::begin() const
{
return const_iterator(&data[0]);
}
int* MyClass::end()
{
return iterator(&data[capacity]);
}
const int* MyClass::end() const
{
return const_iterator(&data[capacity]);
}
Is it still undefined behavior to cast away const from a pointer to an object if only const methods are ever be called after the cast?
I'm trying to implement both an iterator and const_iterator for a class where the dereferenced iterator is a proxy object with a small amount of state and a pointer to the parent object (simplified below)
Although the const qualified proxy only calls const methods on the parent it still requires a non-const pointer in the constructor.
class query {
public:
int get (int r, int c) const;
void set (int r, int c, int v);
class iterator {
iterator (query *q, int r) : m_qry(q), m_row(r) {}
row operator* const () { return row(m_qry, m_row); }
query *m_qry;
int m_row;
};
class const_iterator {
const_iterator (const query *q, int r) : m_qry(q), m_row(r) {}
const row operator* const () {
// protected constructor for row needs cast
return row(const_cast<query *>(m_qry), m_row);
}
const query *m_qry;
int m_row;
};
iterator begin() { return iterator(this, 0); }
const_iterator begin() { return const_iterator(this, 0); }
};
class row {
friend query;
public:
int get (int col) const {
// can be called by both row and const row
return m_qry->get(m_row, col);
}
void set (int col, int v) {
// cannot be called for const row
return m_qry->set(m_row, col, v);
}
protected:
row (query *q, int row) : m_qry(q), m_row(r) {}
private:
query *m_qry;
int m_row;
};
I would prefer to avoid using different classes for the differing iterators as this would require considerable code duplication.
If this is not possible are there any other alternative design patterns with good performance?
In a const method, the this pointer is a const type.
So given that it's implicitly cast back to const, the behaviour is well defined.
Let's say I have a class like this:
class LinkedList
{
struct Node
{
int StoredValue;
// ...
};
Node& GetNodeReference(std::size_t Index)
{
// ...
return NodeReference;
}
public:
int Get(std::size_t Index) const
{
return GetNodeReference(Index).StoredValue;
}
};
This won't compile because the const method Get uses GetNodeReference, which cannot be const because it returns a reference.
How can I work around this?
I'm not sure what you're trying to achieve, but you could provide two overloads of GetNodeReference:
Node& GetNodeReference(std::size_t Index)
{
// ...
return NodeReference;
}
const Node& GetNodeReference(std::size_t Index) const
{
// ...
return NodeReference;
}
Note that the second overload has two const modifers, one at the beginning of the line for the return type and one at the end of the line for the implicitly passed *this object.
To avoid code repetition, you can implement the non-const overload based on the const overload:
const Node& GetNodeReference(std::size_t Index) const
{
// ...
return NodeReference;
}
Node& GetNodeReference(std::size_t Index)
{
return const_cast<Node&>(static_cast<const LinkedList&>(*this).getNodeReference(Index));
}
This technique is discussed in Item 3 of Effective C++ by Scott Meyers.
Don't implement an indexed Get function for lists at all. It will be WAY too easy for a new developer to come in and use it in a loop, turning a linear interation into a polynomial iteration.
If you need such a capability, make a free-function that uses the builtin iterators of the list in conjunction with say std::advance to get the node you want.
If you absolutely need the member function, then the normal approach is the one suggested by #FredOverflow and use overloads (quote his code):
const Node& GetNodeReference(std::size_t Index) const
{
// ...
return NodeReference;
}
Node& GetNodeReference(std::size_t Index)
{
return const_cast<Node&>(static_cast<const LinkedList&>(*this).getNodeReference(Index));
}
How about this?
class LinkedList {
private:
struct Node
{
int StoredValue;
// ...
};
Node NodeReference;
const Node* const GetNodeReference(std::size_t Index) const
{
return &NodeReference;
}
public:
int Get(std::size_t Index) const
{
const Node *const node = GetNodeReference(Index);
return node->StoredValue;
}
};
Edit:
As you can read in the comments
const Node* const GetNodeReference(std::size_t Index) const () ...
should be changed to:
const Node* GetNodeReference(std::size_t Index) const () ...
I suggest:
class LinkedList {
private:
struct Node
{
int StoredValue;
// ...
};
Node NodeReference;
const Node& GetNodeReference(std::size_t Index) const
{
return NodeReference;
}
public:
int Get(std::size_t Index) const
{
const Node node = GetNodeReference(Index);
return node.StoredValue;
}
};