-
A non std::vector<> definition
Hi,
Please take a look at exercise 16 here.
I wrote the code below:
Code:
#include <std_lib_facilities_4.h>
using namespace std;
template <class T> class ovector
{
public:
ovector() = default; // default constructor
ovector(const ovector& N) // Copy constructor
{
for (const auto& v : N.vec)
push_back(new T(*v));
}
ovector& operator= (const ovector& N) // Copy assignment
{
auto l = N;
swap(l.vec, vec);
return *this;
}
~ovector() {
for (auto ptr : vec)
delete ptr;
}
auto begin() const { return vec.begin(); }
auto end() const { return vec.end(); }
auto size() const { return vec.size(); }
void push_back(T* ptr) { vec.push_back(ptr); }
void pop_back() { delete vec.back(); vec.pop_back(); }
void resize(size_t n) { vec.resize(n); }
T& operator*(size_t pos) { return *vec[pos]; }
T& operator[] (size_t pos) { return *vec[pos]; }
const T& operator[] (size_t pos) const { return *vec[pos]; }
private:
vector<T*> vec; // vector of pointers
};
//***************************************
int main() {
ovector<double> v1;
for (size_t i = 0; i < 10; i++)
v1.push_back(new double(2.5*i));
cout << "vector<double> v1 = ";
for (const auto& v : v1)
cout << *v << ' ';
cout << endl;
*v1(0) = 3;
system("pause");
return 0;
}
I get these errors on line 54 where I want to use the overloaded operator* there:
Severity Code Description Project File Line Suppression State
Error (active) E0980 call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type
Severity Code Description Project File Line Suppression State
Error C2064 term does not evaluate to a function taking 1 arguments
What the problem could be please?
-
Re: A non std::vector<> definition
Code:
T& operator*(size_t pos) { return *vec[pos]; }
From this definition of operator*, it is used like this
why?? - which is probably not what you were expecting/wanting.
-
Re: A non std::vector<> definition
Quote:
why?? - which is probably not what you were expecting/wanting.
I haven't ever seen any use like : v1 * 0 = 3;. It looks very awkward. So I think the exercise wants some other declaration of the operator*.
And do you think this code is good as an answer to the exercise?
-
Re: A non std::vector<> definition
You're defined operator* as a binary operator - not as a unary operator that is required when it is used for pointer dereference. For a binary operator you have to provide 2 arguments. When defined as a member function, the first argument is of a class type (eg v1) and the second argument is what is defined for operator*(). In this case a type of size_t. So the syntax to use is eg v1 * 2. What the operator * actually does is decided by the operator() code. It is good practice that what the operator does seems reasonable in the context of someone reading the code - which is why in this case the way it is used does look very awkward. It does work as coded, but is not intuitive as to its meaning when reading code. if I saw v1 * 2 in code and knew that v1 was a vector I would assume that this statement multiplied every element of the vector by 2 - not provide a reference to the second element.
-
Re: A non std::vector<> definition
Quote:
Please take a look at exercise 16 here.
Quote:
15. Define a pvector to be like a vector of pointers except that it contains pointers to objects and its destructor deletes each object.
16. Define an ovector that is like pvector except that the [] and * operators return a reference to the object pointed to by an element rather than the pointer.
How have you implemented the pvector - and the * operator for it? * is not a normal operator (as a pointer deference) for a vector. If the vector held pointers then * would be used to deference a pointer but * would then be an operator for the underlying vector type - not of the vector itself.
-
Re: A non std::vector<> definition
As far as I understood the case for the operator *, we should firstly have something that that operator is defined (overloaded) for, second, some number as an index to refer to the element (pointer) in the ovector, therefore it sounds that we need a binary operator to characterise these two specification. This is my thought. If you think other way, how would you please defined that operator?
Quote:
2. What the operator * actually does is decided by the operator() code.
Do you mean the default operator()? (If any)
Apart from above, I also thought of defining an operator() to be used in main() and it itself calls the operator* for getting the value. No success yet.
Quote:
If the vector held pointers then * would be used to deference a pointer but * would then be an operator for the underlying vector type - not of the vector itself.
I couldn't understand this completely, but here is code for exercise 15:
Code:
#include <std_lib_facilities_4.h>
using namespace std;
template <class T> class pvector
{
public:
pvector() = default; // default constructor
pvector(const pvector& N) // Copy constructor
{
for (const auto& v : N.vec)
push_back(new T(*v));
}
pvector& operator= (const pvector& N) // Copy assignment
{
auto l = N;
swap(l.vec, vec);
return *this;
}
~pvector() {
for (auto ptr : vec)
delete ptr;
}
auto begin() const { return vec.begin(); }
auto end() const { return vec.end(); }
auto size() const { return vec.size(); }
void push_back(T* ptr) { vec.push_back(ptr); }
void pop_back() { delete vec.back(); vec.pop_back(); }
void resize(size_t n) { vec.resize(n); }
T*& operator[] (std::size_t pos) { return vec[pos]; }
const T*& operator[] (std::size_t pos) const { return vec[pos]; }
private:
vector<T*> vec; // vector of pointers
};
-
Re: A non std::vector<> definition
Quote:
2. What the operator * actually does is decided by the operator() code.
Do you mean the default operator()? (If any)
Sorry, my bad. I meant the code for operator*()
Quote:
As far as I understood the case for the operator *, we should firstly have something that that operator is defined (overloaded) for, second, some number as an index to refer to the element (pointer) in the ovector, therefore it sounds that we need a binary operator to characterise these two specification. This is my thought. If you think other way, how would you please defined that operator?
For operator*() on a vector I don't see different - but I wouldn't define operator*() for a vector at all - except as for scalar/vector multiplication. Any other guru got any idea as to what Stroustrup is referring?
-
Re: A non std::vector<> definition
Thank you very much.
For the exercise 17 on the screenshot of the first post, I again can't understand it well enough. :(
We can't give arguments to the destructor to tell it what object it deletes. I try to code it myself but would you please explain the exercise what is its meaning?
-
Re: A non std::vector<> definition
Quote:
Originally Posted by
tomy12
Thank you very much.
For the exercise 17 on the screenshot of the first post, I again can't understand it well enough. :(
We can't give arguments to the destructor to tell it what object it deletes. I try to code it myself but would you please explain the exercise what is its meaning?
Quote:
17. Define an ownership_vector that holds pointers to objects like pvector, but provides a mechanism for the user to decide which objects are owned by the vector (ie which objects are deleted by the destructor). Hint: This exercise is simple if you were awake for chapter 13.
So were you awake for Chapter 13? See 13.10 and Appendix E.4 for the hints!
-
Re: A non std::vector<> definition
Done! thanks.
Does the exercise 18 mean that we should define an iterator (class) for the std::vector<>? But the vector itself has its own begin() and end() for range checking!
And what does "a random access iterator" mean please?
The problem is only understanding the question the way it is meant. Then I myself will write the code.
-
Re: A non std::vector<> definition
See http://www.cplusplus.com/reference/iterator/ for info re the various types of iterator.
I think it means an iterator that can't go out of range. Consider
Code:
vector<int> vi {1,1,1,1,1}
for (auto i = vi.begin(); *i || !*i; ++i);
the iterator i will go out of range as the loop terminator is based upon the value pointed to by the iterator and in this example the termrination condition is always true so i is continually incremented. The 'correct code' is
Code:
vector<int> vi {1,1,1,1,1}
for (auto i = vi.begin(); i != vi.end() && *i || !*i; ++i);
but the exercise seems to want an iterator that is range checked (can't go out of bounds of the container either below or above).
-
Re: A non std::vector<> definition
Thank you.
I've started using this code as a base and will gradually add other features to meet the requirements of a random-access iterator:
Is this base correct up to now?
Code:
#include <std_lib_facilities_4.h>
using namespace std;
template<class T> class rg_ch_vector {
public:
rg_ch_vector() = default; // Default constructor
rg_ch_vector(initializer_list<T> N) { // Constructor with initializers
for (const auto& l : N)
vec.push_back(l);
}
rg_ch_vector& operator=(const rg_ch_vector& N) { // Copy assignment operator
vec = N.vec;
return *this;
}
rg_ch_vector(const rg_ch_vector& N) { // Copy constructor (deep copy)
vec = N.vec;
}
~rg_ch_vector() { // Destructor
~vec();
}
size_t size() const { return vec.size(); }
auto begin() const { return vec.begin(); }
auto end() const { return vec.end(); }
void push_back(const T& v) { vec.push_back(v); }
void push_front(const T& v) { vec.push_front(v); }
void pop_front() { vec.pop_front(); }
void pop_back() { vec.pop_back(); }
T& front() const { return vec.front(); }
T& back() const { return vec.back(); }
void operator++() { ++vec; } // forward
void operator--() { --vec; } // backward
T& operator*() { return *vec; } // get value (dereference)
bool operator==(const rg_ch_vector& b) const { return vec == b.vec; }
bool operator!=(const rg_ch_vector& b) const { return vec != b.vec; }
ostream& operator<<(const T& b) { return b; }
private:
vector<T> vec;
};
//********************************************
int main()
{
rg_ch_vector<double> vd;
vd.push_back(3.5);
vd.push_back(8);
vd.push_back(7.3);
vd.push_back(16);
cout << *vd << ' ';
++vd;
cout << *vd << '\n';
system("pause");
return 0;
}
I get the error illegal indirection in the line 43 (T& operator*()). why please?
And I think the destructor doesn't work as needed either. Any idea about the reason?
And since we haven't any dynamically allocated memory (using new) so there seems to be no need for having a destructor, I suppose.
-
Re: A non std::vector<> definition
Quote:
I get the error illegal indirection in the line 43 (T& operator*()). why please?
vec is of type class vector for which you can't use operator*() to deference. You need to specify an element in the vector to dereference.
Code:
void operator++() { ++vec; } // forward
void operator--() { --vec; } // backward
This isn't right either for the same reason. The iterator should be incremented/decremented not the vector itself.
Quote:
there seems to be no need for having a destructor
Correct with the code as shown as vector has its own destructor which will get called.
-
Re: A non std::vector<> definition
1- I thought since the exercise has specified that we are to define an iterator (a random-access iterator), we must have an iterator. So I went for changing the code this way. I'm still not completely sure if it's exactly what the exercise wants or not. But I also think the issue is simpler than what I've thought of. I defined a class named Iterator. If possible please take a look at this whether it's as a whole right for the exercise up to now.
Code:
#include <std_lib_facilities_4.h>
using namespace std;
template<class T> class rg_ch_vector {
public:
class Iterator;
rg_ch_vector<T>() = default; // Default construtor
rg_ch_vector<T>(initializer_list<T> N) { // Constructor with initializers
for (const auto& l : N)
push_back(l);
}
rg_ch_vector& operator=(const rg_ch_vector& N) { // Copy assignment operator
vec = N.vec;
return *this;
}
rg_ch_vector(const rg_ch_vector& N) { // Copy constructor (deep copy)
vec = N.vec;
}
size_t size() const { return vec->size(); }
Iterator begin() const { return vec.being(); } // iterator to the first element
Iterator end() const { return vec.end(); } // iterator to one beyond the last element
void push_back(const T& v) { vec.push_back(v); } // insert v at end
T& operator[] (std::size_t pos) { return vec[pos]; }
const T& operator[] (std::size_t pos) const { return vec[pos]; }
};
//****************************************
template<class T>
class rg_ch_vector<T>::Iterator {
private:
vector<T>* vec;
friend class rg_ch_vector<T>;
public:
Iterator(vector<T>* p) : vec(p) { }
Iterator& operator++() { Iterator p = vec + 1; return p; } // forward
Iterator& operator--() { Iterator p = vec - 1; return p; } // backward
T& operator*() { return vec*; } // get value (dereference)
bool operator==(const Iterator& b) const { return vec == b.vec; }
bool operator!=(const Iterator& b) const { return vec != b.vec; }
};
//****************************************************************************
int main()
{
rg_ch_vector<int> v;
v.push_back(3);
v.push_back(5);
cout << v[0] << endl;
auto p = v.begin();
++p;
cout << *p << endl;
system("pause");
return 0;
}
2- I get the error below for T& operator*() { return vec*; } // get value (dereference).
error: syntax error: ';'
I think by an element, you meant I should declare a variable type T to be populated by what the member functions of class rg_ch_vector return, so that its value can be used in Iterator class functions like T& operator*(). Incorrect?
-
Re: A non std::vector<> definition
Quote:
But I also think the issue is simpler than what I've thought of. I defined a class named Iterator.
Yes, Recap section 20.4.2
Code:
Iterator begin() const { return vec.being(); } // iterator to the first element
Iterator end() const { return vec.end(); } // iterator to one beyond the last element
Nice, but no. vec.begin() returns type vector::iterator which is not the same as your Iterator class. You need to return your type Iterator.
-
Re: A non std::vector<> definition
I thought of your answer and read the section too and changed the code to:
Code:
#include <std_lib_facilities_4.h>
using namespace std;
template<class T> class rg_ch_vector {
public:
class Iterator;
rg_ch_vector<T>() = default; // Default construtor
rg_ch_vector<T>(initializer_list<T> N) { // Constructor with initializers
for (const auto& l : N)
push_back(l);
}
rg_ch_vector& operator=(const rg_ch_vector& N) { // Copy assignment operator
vec = N.vec;
return *this;
}
rg_ch_vector(const rg_ch_vector& N) { // Copy constructor (deep copy)
vec = N.vec;
}
size_t size() const { return vec.size(); }
Iterator begin() const { return Iterator(vec.begin()); }
// iterator to the first element
Iterator end() const { return Iterator(vec.end()); }
// iterator to one beyond the last element
void push_back(const T& v) { vec.push_back(v); } // insert v at end
T& operator[] (std::size_t pos) { return vec[pos]; }
const T& operator[] (std::size_t pos) const { return vec[pos]; }
protected:
vector<T> vec;
};
//****************************************
template<class T>
class rg_ch_vector<T>::Iterator {
private:
T* iter = nullptr;
friend class rg_ch_vector<T>;
public:
Iterator(T* p) : iter(p) { }
Iterator& operator++() { iter++; return *this; } // forward
Iterator& operator--() { iter--; return *this; } // backward
T& operator*() { return *iter; } // get value (dereference)
bool operator==(const Iterator& b) const { return vec == b.vec; }
bool operator!=(const Iterator& b) const { return vec != b.vec; }
};
//****************************************************************************
int main()
{
rg_ch_vector<int> v1;
v1.push_back(3);
v1.push_back(5);
auto p = v1.begin();
++p;
cout << *p << endl;
system("pause");
return 0;
}
I get an error in line 27 (Iterator begin()) about a non-match conversion.
Look please, when I declare auto p = v1.begin(); in main(), it goes to Iterator begin() const { return Iterator(vec.begin()); } in rg_ch_vector class sending a pointer type T* to Iterator(T* p) : iter(p) { } in the Iterator class.
There, it puts that pointer to iter which is again in type T*.
So in theory nothing looks clearly wrong, but in essence I get that error!
I don't know how to solve that.
-
Re: A non std::vector<> definition
Code:
Iterator begin() const { return Iterator(vec.begin()); }
vec.begin() returns a type of vector::iterator which you are then trying to create a temp instance of Iterator from - but Iterator doesn't have a constructor that takes a type of vector::iterator. As the Iterator constructor requires a pointer to a type, consider
Code:
Iterator begin() const {return (T*)vec.data();}
There is also a similar issue with end().
-
Re: A non std::vector<> definition
What does Iterator(vec.begin() in { return Iterator(vec.begin()); } mean please?
1- Iterator is a (user-defined) type, so doesn't that expression try to convert the type of vector::iterator into the type of an Iterator?
2- Or it tries to call a constructor of the class Iterator with the syntax of
Code:
Iterator(vector::iterator p) : iter(p) { }
?
3- And if 2, would it work? That is, could we assign a vector::iterator type, p, to a T* type iter in the Iterator class?
-
Re: A non std::vector<> definition
Quote:
What does Iterator(vec.begin()) in { return Iterator(vec.begin()); } mean please?
It creates a temp object of class Iterator calling the Iterator class constructor with vec.begin() as the argument. As class Iterator doesn't have a constructor that takes class vector::iterator as an argument, there is a compile error. The class Iterator has only one constructor which takes as argument a type T* (ie a pointer to a type). So the argument used with Iterator( has to be of this type.
So 2) Yes. 3) No. That is why you get the compile error as there is no constructor that takes an argument of vector::iterator for the class Iterator.
-
Re: A non std::vector<> definition
These are begin and end member functions:
Code:
Iterator begin() const { return (T*)(vec.data()); }
Iterator end() const { return (T*)(vec.data()+vec.size()-1);}
Here what is returned is of type vec.data() (a pointer to the first element) which is then converted to a T*. How do I know that conversion will be possible?
And the return type should be of type Iterator, why no error while a T* is not an Iterator?
I defined:
Code:
bool operator==(const Iterator& b) const { return b == *this; }
bool operator!=(const Iterator& b) const { return b != *this; }
and in main():
Code:
rg_ch_vector<int> v1;
v1.push_back(3);
v1.push_back(5);
rg_ch_vector<int> v2 = { 10, 12, 15, 18 };
auto p1 = v1.begin();
auto p2 = v2.begin();
if (p1 == p2) cout << "Equal\n";
My assumption is: in (p1 ==p2), a pointer to p1 will be sent to the operator== as this and *this is that p1.
p2 is sent to b and therefore return b == *this; should work. But I get an error on that operator:
Severity Code Description Project File Line Suppression State
Warning C4717 'rg_ch_vector<int>::Iterator::operator==': recursive on all control paths, function will cause runtime stack overflow
-
Re: A non std::vector<> definition
Quote:
And the return type should be of type Iterator, why no error while a T* is not an Iterator?
Because it creates a temp object of class Iterator with constructor T*.
Code:
bool operator==(const Iterator& b) const { return b == *this; }
*this is of type Iterator, so you are trying
Code:
b.operator==(*this);
which calls Iterator operator==(const Iterator* b) which then calls Iterator operator==(const Iterator* b) and so on for ever!
When coding an operator, the code mustn't call itself!
-
Re: A non std::vector<> definition
I got your point and modified it to this:
Code:
bool operator==(const Iterator& b) const { return iter == b.iter; }
Thanks for guiding me by comments (mostly) and direct me to change the code to what that is right.
One question:
Would this code be the one you'd write if you were offered that exercise? That is, do you accept the code written this way until now and I want to develop it to meet the features of a random-access iterator?
-
Re: A non std::vector<> definition
Quote:
Would this code be the one you'd write if you were offered that exercise?
No, but knowing extra info about c++ that you'll gain. I'd be deriving a new class from the STL class iterator. See http://www.cplusplus.com/reference/iterator/iterator/
-
Re: A non std::vector<> definition
Quote:
No, but knowing extra info about c++ that you'll gain. I'd be deriving a new class from the STL class iterator
Thanks. But I probably should have asked the question this way: "... if you were offered this exercise and would use the stuff covered only in the previous chapters of the book?"
It's right that your version differs from mine because I'm in an almost intermediate level of C++ while you're an expert so you'd use more advanced tools for a given task.
I suppose considering the stuff covered in this point of the book (and it's the only book I've read and am reading still on C++) , and also the context of the exercise 18, what is written up to now is probably acceptable, if you don't disagree.
Here is the code for now (still incomplete though):
Code:
#include <std_lib_facilities_4.h>
using namespace std;
template<class T> class rg_ch_vector {
public:
class Iterator;
rg_ch_vector<T>() = default; // Default construtor
rg_ch_vector<T>(initializer_list<T> N) { // Constructor with initializers
for (const auto& l : N)
push_back(l);
}
rg_ch_vector& operator=(const rg_ch_vector& N) { // Copy assignment operator
vec = N.vec;
return *this;
}
rg_ch_vector(const rg_ch_vector& N) { // Copy constructor (deep copy)
vec = N.vec;
}
size_t size() const { return vec.size(); }
Iterator begin() const { return (T*)(vec.data()); }
// iterator to the first element
Iterator end() const { return (T*)(vec.data()+vec.size());}
// iterator to one beyond the last element
void push_back(const T& v) { vec.push_back(v); } // insert v at end
T& operator[] (std::size_t pos) { return vec[pos]; }
const T& operator[] (std::size_t pos) const { return vec[pos]; }
protected:
vector<T> vec;
};
//****************************************
template<class T>
class rg_ch_vector<T>::Iterator {
private:
T* iter = nullptr;
//friend class rg_ch_vector<T>;
public:
Iterator() = default; // Default construtor
Iterator(T* p) : iter(p) { }
Iterator(const Iterator& N) : iter(N.iter) { } // Copy constructor
Iterator& operator=(const Iterator& N) { iter = N.iter; return *this; }
// Copy assignment operator
Iterator& operator++() { iter++; return *this; } // forward prefix
Iterator& operator--() { iter--; return *this; } // backward prefix
Iterator operator++(T) { Iterator temp(*this); ++*this; return temp; }
// forward postfix
Iterator operator--(T) { Iterator temp(*this); --*this; return temp; }
// backward postfix
Iterator operator+(int i) { iter += i; return *this; } //arithmetic operator +
Iterator operator-(int i) { iter -= i; return *this; } //arithmetic operator -
Iterator operator+=(int i) { iter += i; return *this; } //arithmetic operator +=
Iterator operator-=(int i) { iter -= i; return *this; } //arithmetic operator -=
T& operator*() { return *iter; } // get value (dereference)
T* operator&() { return iter; }
bool operator==(const Iterator& b) const { return iter == b.iter; }
bool operator!=(const Iterator& b) const { return iter != b.iter; }
};
What do you think of it?
A couple of questions:
1- We use delete for an object if it's created using a dynamically allocation from the memory via the operator new. So here we don't have any new, hence don't need any delete either. right?
2- I've defined a couple of constructors for both classes! It looks rather redundant although I'm not sure!
3- In the copy assignment operator:
Code:
Iterator& operator=(const Iterator& N) { iter = N.iter; return *this; }
It works but if I define it this way it shows errors:
Code:
Iterator& operator=(const Iterator& N) : iter(N.iter) {return *this; }
I don't see any logical reason for that difference!
-
Re: A non std::vector<> definition
3. Only a constructor can have a base/member initializer list. As operator=() isn't a constructor, it can't.
Code:
Iterator& operator++() { iter++; return *this; } // forward prefix
Why not
Code:
Iterator& operator++() { ++iter; return *this; } // forward prefix
Code:
Iterator operator++(T) { Iterator temp(*this); ++*this; return temp; }
Why not
Code:
Iterator operator++(T) { Iterator temp(*this); ++iter; return temp; }
Code:
Iterator operator+(int i) { iter += i; return *this; } //arithmetic operator +
Not really. This is operator+=. Operator+ doesn't change this. Hint. Operator+() is often implemented using operator+=().