1

I want to build my own full Vector class in C++. I started like this:

#include <iostream>
#include <initializer_list>

#define Print(x)(std::cout<< x << std::endl)

// Vector Class // 
template <typename T>
class Vector
{
    // Attributes
    int length = 0;
    T* array;

    public:
   
    // Default constructor
    Vector()
    : length(0), array(nullptr)
    { }

    // Copy constructor 
    template<typename U>
    Vector(const Vector<U>& other)
        : Vector(other.len())
    {
        Print("Use Copy Constructor");
        // Coppying other data to new array
        array = new T[other.len()];
        for (auto i=0; i < other.len(); i++)
            array[i] = other[i];
    }

    // Move constructor
    Vector(Vector<T>&& other)
        : length(other.len()), array(other.array)
    {
        Print("Use Move Constructor");
        // Deleting other array
        other.length = 0;
        other.array = nullptr;
    }

    // Constructor (does not allow uniform initialisation)
    Vector(int length)
    : length(length), array(new T[length])
    { }

    // Constructor (with initialiser list and delegate constructor)
    Vector(std::initializer_list<T> list)
    : Vector((int)list.size())
    {
        std::uninitialized_copy(list.begin(), list.end(), array);
    }

    // Destructor
    ~Vector()
    {
        length = 0;
        delete[] array;
        array = nullptr;
    }

    // Function Len that returns the length 
    int len() const
    {
        return length;
    }
    // Operator[](int i) and its const overload
    auto& operator[](int i)
    {
        return array[i];
    }
    
    auto& operator[](int i) const
    {
        return array[i];
    }

    // Copy assignment operator 
    template<typename U>
    Vector& operator=(const Vector<U>& other)
    {
        Print("Use Copy Operator");
        if (this != (Vector*)& other) {
            /*
            This works the same way but does not solve the problem: 
    
            Vector<typename std::common_type<T,U>::type> temp(other);
            temp.swap(*this); 
            */ 

            delete[] array;
            length = other.len();
            array = new T[other.len()];
            for (auto i = 0; i < other.len(); i++)
                array[i] = other[i];
        }
        return *this;
    }

    // Move assignment opertator
    Vector& operator=(Vector<T>&& other)
    {
        Print("Use Move Operator");
        if (this != (Vector*)&other){
            /*
            This works the same way but does not solve the problem: 

            Vector<T> temp(std::move(other)); // moves the array
            temp.swap(*this);
            */ 

            delete[] array;
            length = other.len();
            array   = other.array;
            other.len() = 0;
            other.array   = nullptr;
        }
        return *this;
    }
};

But if I now try to use the copy assignment operator like this:

Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3};
Vector<double> a = double_vector;

I get the following error message:

error: use of deleted function 'constexpr Vector<double>::Vector(const Vector<double>&)'

I assume that the problem lies within the copy constructor and copy assignment operator, but I sadly can't find a solution. What I find strange is that, if I comment out the move constructor and move assignment operator, the code does seem to work. This lets me think that the compiler has difficulty knowing which constructor to use. But I could also be very wrong about this.

Hope I gave enough info for an answer/push in the right direction.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
DvB
  • 41
  • 3
  • 1
    Warning: The `: Vector(other.len())`delegates to `Vector(int length)` which allocates storage. That storage is leaked in the copy constructor at `array = new T[other.len()];`. – user4581301 Feb 09 '22 at 23:19
  • Solution: Remove the templates in the template. they don't make much sense here. `template Vector(const Vector &other)` -> `Vector(const Vector &other)`. A `Vector` specialized on `U` may not be the same as a `Vector` specialized on `T`, so the copy constructor stops being a copy constructor. More details at [Why doesn't the standard consider a template constructor as a copy constructor?](https://stackoverflow.com/questions/55845896/why-doesnt-the-standard-consider-a-template-constructor-as-a-copy-constructor) – user4581301 Feb 09 '22 at 23:30
  • I recommend doing the same to all of the other template methods inside the `Vector` template – user4581301 Feb 09 '22 at 23:31
  • Why did you decide to template the copy constructor and assignment operator, anyway? There's an interesting story, a lesson to be learned, or maybe both, there. – user4581301 Feb 09 '22 at 23:38
  • Thanks for the answer. When trying to compute Vector double_vector = {3.4677, 3.212, 2.2, 6.3}; Vector a = double_vector; It is indeed sufficient to remove the template. However, I also want to be able to compute: Vector double_vector = {3.4677, 3.212, 2.2, 6.3}; Vector b = double_vector; b.display(); And: Vector integer_vector = {3, 2, 4, 7}; Vector d = integer_vector; d.display(); This does however not work when the template is removed. – DvB Feb 10 '22 at 12:44
  • What I now did, which works. Is make one Copy constructor and assignment operator with the template, and one without! This then works in all the cases. – DvB Feb 10 '22 at 12:50

1 Answers1

2

A template is never a copy constructor, that is a converting constructor.

And as you have defined a bunch of other constructors, the otherwise default copy constructor will be defined as deleted.

BoP
  • 2,310
  • 1
  • 15
  • 24
  • Near as I can tell, the right diagnosis, but I recommend adding a solution. – user4581301 Feb 09 '22 at 23:36
  • @user4581301 - I thought the first sentence made it "obvious" for the OP to add a copy constructor that is **not** a template. – BoP Feb 09 '22 at 23:38
  • Me, I'd remove the templating, but I see your point. With a bit of SFINAE to ensure the contained types are convertible the converting constructor might be useful. – user4581301 Feb 09 '22 at 23:41