0

For a 3-vector class

template <typename T>
class vec3 {

   template <typename U>
   friend std::ostream& operator<<(std::ostream& out, const vec3<U>& v);

   template <typename U>
   friend std::istream& operator>>(std::istream& in, vec3<U>& v);

   protected:
   std::vector<T> data;

   public:
   vec3 (                    ): data(3)
        {}; // default constructor

   vec3 ( T x,   T y,   T z  ): data(3)
        { data[0] = x; data[1] = y; data[2] = z; } // constructor from 3 scalars

   vec3 ( T* xyz             ): data(3)
        { std::copy (xyz, xyz+3, data.begin() ); } // constructor from pointer

   vec3 ( const vec3<T>& rhs ): data(3)
        { std::copy ( rhs.data.begin(), rhs.data.end(), data.begin() ); } // copy constructor

   vec3<T> operator=( vec3<T> rhs ) {
        std::copy( rhs.data.begin(), rhs.data.end(), data.begin() ); // assignment    
        return (*this);
   }

   // passing on the [] operator for accessing elements
   T& operator[] ( size_t offset)       
         { return data[offset]; } // write access
   const T& operator[] ( size_t offset) const 
         { return data[offset]; } // read  access

   // left += and + for elements and vectors
   template <typename U>
   const vec3<T>& operator+= ( const U& rhs )       
         { data[0]+=rhs;    data[1]+=rhs;    data[2]+=rhs;    return (*this); }
   template <typename U>
   const vec3<T>& operator+= ( const vec3<U>& rhs ) 
         { data[0]+=rhs[0]; data[1]+=rhs[1]; data[2]+=rhs[2]; return (*this); }
   template <typename U>
   const vec3<T> operator+   ( const U& rhs )       
         { vec3<T> out(*this); out += rhs; return out;                        }

   // left *= and * for elements and vectors
   template <typename U>
   const vec3<T>& operator*= ( const U& rhs )       
         { data[0]*=rhs;    data[1]*=rhs;    data[2]*=rhs;    return (*this); }
   template <typename U>
   const vec3<T>& operator*= ( const vec3<U>& rhs ) 
         { data[0]*=rhs[0]; data[1]*=rhs[1]; data[2]*=rhs[2]; return (*this); }
   template <typename U>
   const vec3<T> operator*   ( const U& rhs )       
         { vec3<T> out(*this); out *= rhs; return out;                        }

   // rest of the operators

}

template <typename U>
std::ostream& operator<<(std::ostream& out, const vec3<U>& v)
   { return out << '(' << v.data[0] << ',' << v.data[1] << ',' << v.data[2] <<')'; }

template <typename U>
std::istream& operator>>(std::istream& in , vec3<U> &v)
   { return in >> v.data[0] >> v.data[1] >> v.data[2]; }

I tried to run this bit of code

float v[3] = { 10, 20, 30 };

vec3<float> v1 (v);
std::cout << v1 << " \n";
vec3<float> v2 (v1);
std::cout << v2 << " \n";
vec3<float> v3 = v2;
std::cout << v3 << " \n \n";

v3+=1.;
std::cout << v3 << " \n";
v3=v1+v2*2;
std::cout << v3 << " \n";

which returns

(10,20,30) 
(10,20,30) 
(10,20,30) 

(11,21,31) 
Segmentation fault

So I'm confident enough about the copy constructor, assignment etc. but is it not possible to pass on the result of a * operation to a +? It returns a const vec3<T> so what is going wrong here? Some rookie mistake I guess but I don't see it.

alle_meije
  • 2,424
  • 1
  • 19
  • 40
  • 4
    Typically, you will want to return `T&` and not `const T&` from your `+=` and `*=` operators. You should take a moment to read [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading). – François Andrieux Feb 03 '20 at 20:10
  • 2
    It's pretty likely the issue is in your ctors or assignment -- you should show them (and your member vars) – Lou Franco Feb 03 '20 at 20:11
  • If your return type is not a reference and not a pointer then it should not be `const`. Making the return value `const` in these cases does not provide anything and instead disables move semantics and optimizations. – François Andrieux Feb 03 '20 at 20:11
  • That edit link is a nice touch... – anastaciu Feb 03 '20 at 20:11
  • 1
    Also, why use dynamic allocation for 3 elements? There is `std::array` for that purpose. – ALX23z Feb 03 '20 at 20:35
  • Apologies. This is enough code of the vec3 class to compile the example. I'll try to be concise & complete. – alle_meije Feb 03 '20 at 20:40
  • I copied your code, and it works and I get `(11,21,31) (30,60,90)` on last two lines in the output. hm... You used `10,20,0` in the output you showed, you posted code with `v[3] = { 10, 20, 30 };`. Yet with `v[3] = {10,20,0}` it still works. [godbolt](https://godbolt.org/z/H8J5oc) Is something maybe missing? What compiler do you use? What system do you use? Is there some else code that maybe can be related? Did you debug the code to pinpoint the exact location of segfault? Are you sure that segfault occurs here and not somewhere else, the output of last `cout` may just be buffered. – KamilCuk Feb 03 '20 at 20:45
  • Oops @KamilCuk that was a slip of the keyboard. But that is very weird. I am using g++ 9.2.1 on Debian Stretch (in CodeBlocks). The program ends after that last line. There is some more stuff in vec3 but that is not used. – alle_meije Feb 03 '20 at 20:58
  • 1
    :/ godbolt uses gcc9.2. What options do you pass to gcc? Can you post your code to an online compiler and reproduce the problem? I remember CodeBlocks has a simple fun-to-use debugger frontent. – KamilCuk Feb 03 '20 at 21:00
  • I put it all in as one file here https://godbolt.org/z/Jz93y8 (commenting out includes etc) but it does not show any output... – alle_meije Feb 03 '20 at 22:14

1 Answers1

0
v3=v1+v2*2;

this line makes recursive calls of function

template <typename T, typename U>
inline vec3 <T> operator+ (U x, vec3 <T> y) {
    return y + x;
}

it gives segmentation fault after stack overflow. if you remove this function, member function const vec3<T> operator+ ( const U& rhs )will be called for operation and it works fine.

you should add global operator function that you defined to your question.

idris
  • 488
  • 3
  • 6
  • I can't see that `y + x` method in the question ? Also, I don't see how that could be a problem for _some_ compilers. Either that's a recursive call or not. Whether it is depends on other overloads. – MSalters Feb 04 '20 at 12:52
  • in comment @alle_meije posted his whole code to godbolt.org/z/Jz93y8. he didnt posted the method in the question. for vec3 + vec3 operation it need to call y + x what is vec3 + vec3. it calls itself endlessly. – idris Feb 04 '20 at 13:02
  • Thanks! I had not put it in the original post because I did not see it as part of the problem... Now I see that this also covers the case where U is a vec3. I used this to cover lots of scalar types to be added to a vector. Back to the drawing board. – alle_meije Feb 04 '20 at 14:12
  • removing the `typename U` and then defining the inline function above for `T x, vec3 y` works. I had tried to also cover the case to add, say, an `int` to a `vec3 ` with the previous version. – alle_meije Feb 19 '20 at 16:12