patterncppModerate
Custom mathematical vector class
Viewed 0 times
customclassvectormathematical
Problem
My first bigger C++ project: a vector class for personal use and statistical computation.
```
#include
#include
#include
#include
template
class vect
{
std::vector m;
size_t s;
public:
// default constructor
vect(): m(0), s(0){}
// overloaded constructor
vect(size_t n) :m(n), s(n) {}
vect(std::vector v) :m(v), s(v.size()) {}
// copy constructor
vect(const vect&v): m(v.getData()), s(v.size()){}
// destructor
~vect(){}
std::vector getData() const{
return m;
}
size_t size() const {
return s;
}
void addTo(T value){
m.push_back(value);
s++;
}
void addAt(T value, size_t loc=0){
s++;
m.emplace(m.begin()+loc, value);
}
void rmFrom(){
m.pop_back();
s--;
}
void rmAt(size_t loc){
m.erase(m.begin()+loc);
s--;
}
// returns a sorted copy of the original vector.
vect sorted(){
std::vector temp = this->getData();
std::sort(temp.begin(), temp.end());
vect v(temp);
return v;
}
double median(){
// linearly interpolated
if (s%2==0)
{
return ((this->sorted()[(s/2)-1]+this->sorted()[(s/2)])/2);
}
else
{
return (this->sorted()[(s)/2]);
}
}
double percentile(double p){
// @p - value between 0 and 1: the percentile
// rounds to the nearest index and return the corresponding
return (this->sorted()[round(s*p)]);
}
double sum(){
// computes the sum of the vectors elements
double sum = 0;
size_t l = 0;
while (lsum()/s;
}
double dot(){
// computes the inner product of this vector
vect temp = *this;
double dot = 0;
size_t l = 0;
while(l other){
// computes the inner product of this and another vector
vect temp = *this;
double dot
```
#include
#include
#include
#include
template
class vect
{
std::vector m;
size_t s;
public:
// default constructor
vect(): m(0), s(0){}
// overloaded constructor
vect(size_t n) :m(n), s(n) {}
vect(std::vector v) :m(v), s(v.size()) {}
// copy constructor
vect(const vect&v): m(v.getData()), s(v.size()){}
// destructor
~vect(){}
std::vector getData() const{
return m;
}
size_t size() const {
return s;
}
void addTo(T value){
m.push_back(value);
s++;
}
void addAt(T value, size_t loc=0){
s++;
m.emplace(m.begin()+loc, value);
}
void rmFrom(){
m.pop_back();
s--;
}
void rmAt(size_t loc){
m.erase(m.begin()+loc);
s--;
}
// returns a sorted copy of the original vector.
vect sorted(){
std::vector temp = this->getData();
std::sort(temp.begin(), temp.end());
vect v(temp);
return v;
}
double median(){
// linearly interpolated
if (s%2==0)
{
return ((this->sorted()[(s/2)-1]+this->sorted()[(s/2)])/2);
}
else
{
return (this->sorted()[(s)/2]);
}
}
double percentile(double p){
// @p - value between 0 and 1: the percentile
// rounds to the nearest index and return the corresponding
return (this->sorted()[round(s*p)]);
}
double sum(){
// computes the sum of the vectors elements
double sum = 0;
size_t l = 0;
while (lsum()/s;
}
double dot(){
// computes the inner product of this vector
vect temp = *this;
double dot = 0;
size_t l = 0;
while(l other){
// computes the inner product of this and another vector
vect temp = *this;
double dot
Solution
C++14
Its 2014 most modern compilers now support C++14 so you should use it. This code is still very C++03. For this class this simply means adding move semantics (and nothrow on swap).
To add move semantics you need to add a move constructor and move assignment operator.
Potentially there are a couple of places where you can use range based for operator.
General
This seems redundant (and thus dangerous).
The size is already stored as part of the the other member
Const Correctness
None of these functions
modify the state of your vector. So you should mark them as const members.
This allows you pass your
Efficiency
You may want to cache the sum in a mutable member. Invalidate it if the vector is mutated. There is no point re-computing this value if the vector has not changed.
Also prefer to use some of the algorithms that are built for you when you can.
Copy and Swap
This is an old way of doing this:
The more modern way is to use the copy and swap idium.
The
Example:
Define the
Once you studied that and see it does the same. There is a small optimization.
Your streaming operations should be symmetrical and distinguishable.
The output operator dumps the whole vector:
But the read operator only reads a single value into the vector (so its not symmetrical).
Personally I would make it dump the data in a way that makes it obvious of the start/end point (or) you can prefix the dump with a count and then the values.
Its 2014 most modern compilers now support C++14 so you should use it. This code is still very C++03. For this class this simply means adding move semantics (and nothrow on swap).
To add move semantics you need to add a move constructor and move assignment operator.
vect(vect&& other);
vect& operator=(vect&& other);Potentially there are a couple of places where you can use range based for operator.
General
This seems redundant (and thus dangerous).
size_t s;The size is already stored as part of the the other member
m;Const Correctness
None of these functions
double sum();
double mean();
double dot();modify the state of your vector. So you should mark them as const members.
double sum() const;
double mean() const;
double dot() const;This allows you pass your
vect to a function as a const reference and still call these non mutating functions.Efficiency
You may want to cache the sum in a mutable member. Invalidate it if the vector is mutated. There is no point re-computing this value if the vector has not changed.
double sum(){
// computes the sum of the vectors elements
double sum = 0;
size_t l = 0;
while (l<s) {
sum+=m[l];
l++;
}
return sum;
}Also prefer to use some of the algorithms that are built for you when you can.
sum = std::accumulate(m.begin(), m.end());Copy and Swap
This is an old way of doing this:
// overloaded operators
vect& operator=(const vect& other){
if (this!=&other)
{
m = other.getData();
s = other.size();
}
return *this;
}The more modern way is to use the copy and swap idium.
// overloaded operators
vect& operator=(vect other){ // Notice the pass by value to get the copy.
other.swap(*this); // Swap the content of this object.
// With the copy you just created. This updates it
// in an exception safe way,
return *this; // return yourself.
} // Let the destructor of other cleanup your old state.
void swap(vect& other) throws() { // use C++11 nothrow if you upgrade to C++11
std::swap(this->m, other.m);
std::swap(this->s, other.s);
}The
X operators can be written in terms of the X= operator.Example:
Define the
+ operator in terms of the += operator.template
vect operator+(const vect& a, const vect& b)
{
vect result(a); // Make a copy.
result += b;
return result;
}Once you studied that and see it does the same. There is a small optimization.
template
vect operator+(const vect copy, const vect& b)
{
copy += b; // Notice the copy is passed by value.
// So there is an implicit copy
// So you don't need the manual copy inside the code.
return copy;
}Your streaming operations should be symmetrical and distinguishable.
The output operator dumps the whole vector:
template
std::ostream& operator&v){
for(int i = 0; i < v.size(); i++){
os << v.getData()[i] << " ";
}
return os;
}But the read operator only reads a single value into the vector (so its not symmetrical).
template
std::istream& operator>>(std::istream& is, vect& v){
T value;
is >> value; // Also note. That if the read fails.
v.addTo(value); // you are still adding it to the vector.
// You should probably test to make sure the read works.
// if (is >> value) {v.addTo(value);}
return is;
}Personally I would make it dump the data in a way that makes it obvious of the start/end point (or) you can prefix the dump with a count and then the values.
template
std::ostream& operator&v){
os
std::istream& operator>>(std::istream& is, vect& v){
std::size s = 0;
char marker = 'B';
if (is >> s >> marker)
{
if (marker != ':')
{ // The mark is not what we expect.
// So mark the stream as bad so that processing stops.
is.setstate(std::ios::failbit);
}
else
{
T value;
for(;s > 0 && (is >> value);--s)
{
// Have values and successful read.
v.addTo(value);
}
}
}
return is;
}Code Snippets
vect(vect&& other);
vect& operator=(vect&& other);double sum();
double mean();
double dot();double sum() const;
double mean() const;
double dot() const;double sum(){
// computes the sum of the vectors elements
double sum = 0;
size_t l = 0;
while (l<s) {
sum+=m[l];
l++;
}
return sum;
}sum = std::accumulate(m.begin(), m.end());Context
StackExchange Code Review Q#63970, answer score: 16
Revisions (0)
No revisions yet.