It’s impossible to tell what’s wrong without a Minimal, Complete, Verifiable Example. In this case, that means the relevant parts of your class definition and a main()
function.
In case this helps, here’s an example of three different ways to write an efficient operator+
and an operator-
. They use some fairly advanced techniques. The implementation of operator+
relies on the compiler to use the provided move constructor and optimize away any redundant copies. The implementation of operator-
calls a programmatic constructor that uses a dummy parameter for the unary version, then a function object for the binary version.
#include <array>
#include <cassert>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <new>
#include <utility>
#include <vector>
using std::cout;
using std::endl;
using std::size_t;
// A four-element vector, implemented internally with std::vector.
class vec4i {
private:
static constexpr size_t size = 4U;
/* Object holding the vector data. The compiler knows how to destroy it,
* so we do not need to write our own destructor.
*/
std::vector<int> data;
/* Empty class used as a dummy parameter to tell the compiler that we are
* calling the programmatic constructor, not the copy constructor.
*/
struct op_opposite {};
// Programmatic constructor used by unary operator-:
vec4i( const vec4i& v, const op_opposite& /* unused */ )
: vec4i()
{
for (size_t i = 0; i < size; ++i)
data[i] = -v[i];
}
/* The type of a generic function object implementing a binary function. */
using binary_fun = std::function<int(const int, const int)>;
/* We're going to demonstrate a different approach for operator-, a
* programmatic constructor using an arbitrary binary function object from
* <functional>.
*/
vec4i( const vec4i& u, const vec4i& v, const binary_fun f )
: vec4i()
{
for ( size_t i = 0; i < size; ++i )
data[i] = f(u[i], v[i]);
}
public:
// Default constructor initializes matrix to zeroes:
vec4i() : data(size) {}
// Constructors that provide values:
vec4i( const std::vector<int>& v ) : data(v) {}
vec4i( const int x, const int y, const int z, const int w )
: data{x,y,z,w}
{}
vec4i( const int v[size] )
: data(size)
{
for ( size_t i = 0; i < size; ++i )
data[i] = v[i];
}
// Copy constructor that makes a deep copy:
vec4i(const vec4i& v) : data(v.data) {}
// Move constructor that avoids a deep copy:
vec4i(vec4i&& v) : data(std::move(v.data))
{}
// One final example, using STL iterators, since it's a one-liner:
vec4i(const std::array<int, size>& a) : data(a.begin(), a.end()) {}
/* Provide an assignment operator from any object that can be used to
* construct this type. Ensure that the class does not assign from its own
* internal data.
*/
template<class T> vec4i& operator=(const T& v)
{
// Check for self-assignment.
if ((void*)this != (void*)&v) {
// Call the destructor, then create a new object in-place.
this->~vec4i();
new(this) vec4i(v);
}
return *this;
}
vec4i operator=(vec4i&& v)
// A more efficient assignment that moves rather than copies the data:
{
if ((void*)this != (void*)&v) {
data.clear();
data.swap(v.data); // Could also write: data = std::move(v.data);
}
return *this;
}
// Accessor returning a rvalue:
int operator[]( const size_t i ) const
{
return data[i];
}
// Accessor returning a lvalue:
int& operator[]( const size_t i )
{
return data[i];
}
// The implementation of operator+ that this example is demonstrating:
vec4i operator+(const vec4i& v) const
{
vec4i temp;
for ( size_t i = 0; i < size; ++i )
temp[i] = data[i] + v[i];
/* Since we provided a move constructor and move assignment above, the
* compiler should be able to optimize away this copy!
*/
return temp;
}
// Returns a vector with the sign of each elemeent flipped:
vec4i operator-(void) const
{
// The dummy second parameter selects the programmatic constructor.
return vec4i( *this, op_opposite() );
}
// Now we use the constructor above to construct the return value:
vec4i operator-(const vec4i& v) const
{
// Function object wrapping a-b, initialized once:
static const binary_fun subtract = std::minus<int>();
// Create the returned temporary object in place.
return vec4i( *this, v, subtract );
}
};
std::ostream& operator<<( std::ostream& os, const vec4i& v )
// Serialize our vector.
{
return os <<
'<' << v[0] << ',' << v[1] << ',' << v[2] << ',' << v[3] << '>';
}
int main(void)
{
const vec4i u = {0,0,0,1}, v = {1,0,0,0};
// Output: "<1,0,0,1>"
cout << u+v << endl;
// Output: "<-1,0,0,1>"
cout << u-v << endl;
// output: "<-1,0,0,1>"
cout << -(v-u) << endl;
return EXIT_SUCCESS;
}