HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Custom mathematical vector class

Submitted by: @import:stackexchange-codereview··
0
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

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.

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.