tags:

views:

103

answers:

1

I'm writing a simple nD-vector class, but am encountering a strange bug. I've stripped out the class to the bare minimum that still reproduces the bug:

#include <iostream>

using namespace std;

template<unsigned int size> class nvector
{
public:
  nvector() {data_ = new double[size];}
  ~nvector() {delete[] data_;}

  template<unsigned int size2> 
  nvector(const nvector<size2> &other)
  {
    data_ = new double[size];
    int i=0;
    for(; i<size && i < size2; i++)
      data_[i] = other[i];

    for(; i<size; i++)
      data_[i] = 0;
  }

  double &operator[](int i) {return data_[i];}
  const double&operator[](int i) const {return data_[i];}

private:
  const nvector<size> &operator=(const nvector<size> &other); //Intentionally unimplemented for now

  double *data_;
};

int main()
{
  nvector<2> vector2d;
  vector2d[0] = 1;
  vector2d[1] = 2;

  nvector<3> vector3d(vector2d);
  for(int i=0; i<3; i++)
    cout << vector3d[i] << " ";
  cout << endl; //Prints 1 2 0

  nvector<3> other3d(vector3d);
  for(int i=0; i<3; i++)
    cout << other3d[i] << " ";
  cout << endl; //Prints 1 2 0
} //Segfault???

On the surface this seems to work fine, and both tests print out the correct values. However, at the end of main the program crashes with a segfault, which I've traced to nvector's destructor.

At first I thought the (incorrect) default assignment operator was somehow being called, which is why I added the (currently) unimplemented explicit assignment operator to rule this possibility out.

So my copy constructor must be buggy, but I'm having one of those days where I'm staring at extremely simple code and just can't see it. Do you guys have any ideas?

+10  A: 

Templated implementation of conversion-constructor is never considered as a candidate function for a copy-constructor. Your templated copy-constructor is never called. Instead, the compiler uses an implicitly generated "default" copy-constructor implementation, which performs shallow copying with obvious consequences.

In other words, the templated constructor you have implemented above will never be used as a copy-constructor, only as a conversion-constructor. You have to implement your copy-constructor explicitly as a non-template function.

AndreyT
Meaning your allocated array is doubly deleted - once by each object pointing to it.
CuppM
Doh! This was the problem. Thanks!
@AndreyT i just noticed the change in the FCD and removed my comment. My comment was only true about C++03 and the pre-FCD '0x draft. Apparently they fixed the issue :) (removing the footnote on 12.8/2, and providing a better example at 12.8/7)
Johannes Schaub - litb
@Johannes Schaub: Oh, I see the footnote. Interesting.
AndreyT